|
@@ -0,0 +1,247 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <a-card>
|
|
|
+ <div class="table-page-search-wrapper">
|
|
|
+ <a-form layout="inline" @submit.prevent="handleSearch">
|
|
|
+ <a-row :gutter="48">
|
|
|
+ <a-col :md="6" :sm="24">
|
|
|
+ <a-form-item label="请求IP">
|
|
|
+ <a-input v-model:value="queryParam.requestIp" placeholder="请输入请求IP" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :md="6" :sm="24">
|
|
|
+ <a-form-item label="用户ID">
|
|
|
+ <a-input v-model:value="queryParam.uid" placeholder="请输入用户ID" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :md="6" :sm="24">
|
|
|
+ <a-form-item label="规则ID">
|
|
|
+ <a-input v-model:value="queryParam.ruleId" placeholder="请输入规则ID" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :md="6" :sm="24">
|
|
|
+ <a-form-item label="实例ID">
|
|
|
+ <a-input v-model:value="queryParam.hostId" placeholder="请输入实例ID" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :md="6" :sm="24">
|
|
|
+ <a-form-item label="API">
|
|
|
+ <a-input v-model:value="queryParam.api" placeholder="请输入API路径" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :md="6" :sm="24">
|
|
|
+ <a-form-item label="API名称">
|
|
|
+ <a-input v-model:value="queryParam.apiName" placeholder="请输入API名称" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :md="6" :sm="24">
|
|
|
+ <a-form-item label="API类型">
|
|
|
+ <a-select v-model:value="queryParam.apiType" placeholder="请选择API类型" allow-clear>
|
|
|
+ <a-select-option value="get">get</a-select-option>
|
|
|
+ <a-select-option value="add">add</a-select-option>
|
|
|
+ <a-select-option value="delete">delete</a-select-option>
|
|
|
+ <a-select-option value="edit">edit</a-select-option>
|
|
|
+ </a-select>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :md="6" :sm="24">
|
|
|
+ <a-form-item label="名称">
|
|
|
+ <a-input v-model:value="queryParam.name" placeholder="请输入名称" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :md="24" :sm="24">
|
|
|
+ <span class="table-page-search-submitButtons">
|
|
|
+ <a-button type="primary" @click="handleSearch">查询</a-button>
|
|
|
+ <a-button style="margin-left: 8px" @click="resetSearch">重置</a-button>
|
|
|
+ </span>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </a-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <a-table
|
|
|
+ :columns="columns"
|
|
|
+ :row-key="record => record.id"
|
|
|
+ :data-source="dataSource"
|
|
|
+ :loading="loading"
|
|
|
+ :pagination="pagination"
|
|
|
+ @change="handleTableChange"
|
|
|
+ :scroll="{ x: 'max-content' }"
|
|
|
+ bordered
|
|
|
+ size="middle"
|
|
|
+ >
|
|
|
+ <template #bodyCell="{ column, record }">
|
|
|
+ <template v-if="column.dataIndex === 'action'">
|
|
|
+ <a-button type="link" @click="goToInfo(record.id)">详情</a-button>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </a-table>
|
|
|
+ </a-card>
|
|
|
+
|
|
|
+ <!-- WAF日志详情模态框 -->
|
|
|
+ <waf-log-detail-modal ref="detailModalRef" />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted } from 'vue';
|
|
|
+import { getWafLogList } from '~/api/waf/waflog.js';
|
|
|
+import WafLogDetailModal from './components/waf-log-detail-modal.vue';
|
|
|
+
|
|
|
+const loading = ref(false);
|
|
|
+const dataSource = ref([]);
|
|
|
+const pagination = ref({
|
|
|
+ current: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0,
|
|
|
+ showTotal: (total) => `共 ${total} 条`,
|
|
|
+ showSizeChanger: true,
|
|
|
+ pageSizeOptions: ['10', '20', '50', '100'],
|
|
|
+ showQuickJumper: true,
|
|
|
+});
|
|
|
+
|
|
|
+const queryParam = ref({
|
|
|
+ requestIp: '',
|
|
|
+ uid: '',
|
|
|
+ ruleId: '',
|
|
|
+ hostId: '',
|
|
|
+ api: '',
|
|
|
+ apiName: '',
|
|
|
+ apiType: '',
|
|
|
+ name: '',
|
|
|
+});
|
|
|
+
|
|
|
+const columns = [
|
|
|
+ { title: 'ID', dataIndex: 'id', fixed: 'left', width: 80 },
|
|
|
+ { title: '用户ID', dataIndex: 'uid', width: 100 },
|
|
|
+ { title: '名称', dataIndex: 'name', width: 150, ellipsis: true },
|
|
|
+ { title: '请求IP', dataIndex: 'requestIp', width: 140 },
|
|
|
+ { title: '实例ID', dataIndex: 'hostId', width: 100 },
|
|
|
+ { title: '规则ID', dataIndex: 'ruleId', width: 100 },
|
|
|
+ { title: 'User Agent', dataIndex: 'userAgent', width: 250, ellipsis: true },
|
|
|
+ { title: 'API', dataIndex: 'api', width: 180, ellipsis: true },
|
|
|
+ { title: 'API名称', dataIndex: 'apiName', width: 150, ellipsis: true },
|
|
|
+ { title: 'API类型', dataIndex: 'apiType', width: 100 },
|
|
|
+ { title: '创建时间', dataIndex: 'createdAt', width: 180 },
|
|
|
+ { title: '更新时间', dataIndex: 'updatedAt', width: 180 },
|
|
|
+ { title: '操作', dataIndex: 'action', fixed: 'right', width: 100 },
|
|
|
+];
|
|
|
+
|
|
|
+const fetchData = () => {
|
|
|
+ loading.value = true;
|
|
|
+
|
|
|
+ // 构造请求参数,并处理特殊类型
|
|
|
+ const params = {
|
|
|
+ requestIp: queryParam.value.requestIp || '',
|
|
|
+ uid: queryParam.value.uid ? parseInt(queryParam.value.uid) : '',
|
|
|
+ ruleId: queryParam.value.ruleId ? parseInt(queryParam.value.ruleId) : '',
|
|
|
+ hostId: queryParam.value.hostId ? parseInt(queryParam.value.hostId) : '',
|
|
|
+ api: queryParam.value.api || '',
|
|
|
+ apiName: queryParam.value.apiName || '',
|
|
|
+ apiType: queryParam.value.apiType || '',
|
|
|
+ name: queryParam.value.name || '',
|
|
|
+ current: pagination.value.current,
|
|
|
+ pageSize: pagination.value.pageSize,
|
|
|
+ column: 'id',
|
|
|
+ order: 'desc'
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('发送WAF日志查询参数:', params);
|
|
|
+
|
|
|
+ getWafLogList(params).then(response => {
|
|
|
+ // 根据实际返回格式处理数据
|
|
|
+ if (response && response.code === 0 && response.data) {
|
|
|
+ const apiData = response.data;
|
|
|
+ if (apiData.records && Array.isArray(apiData.records)) {
|
|
|
+ dataSource.value = apiData.records;
|
|
|
+ pagination.value.total = apiData.total || 0;
|
|
|
+ pagination.value.current = apiData.page || 1;
|
|
|
+ pagination.value.pageSize = apiData.pageSize || 10;
|
|
|
+ } else {
|
|
|
+ dataSource.value = [];
|
|
|
+ pagination.value.total = 0;
|
|
|
+ console.warn('响应中无WAF日志数据记录');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ dataSource.value = [];
|
|
|
+ pagination.value.total = 0;
|
|
|
+ console.error('无效的WAF日志响应格式或响应错误', response);
|
|
|
+ }
|
|
|
+ loading.value = false;
|
|
|
+ }).catch((error) => {
|
|
|
+ console.error('WAF日志请求失败:', error);
|
|
|
+ dataSource.value = [];
|
|
|
+ loading.value = false;
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleTableChange = (pager) => {
|
|
|
+ pagination.value.current = pager.current;
|
|
|
+ pagination.value.pageSize = pager.pageSize;
|
|
|
+ fetchData();
|
|
|
+};
|
|
|
+
|
|
|
+const handleSearch = () => {
|
|
|
+ pagination.value.current = 1;
|
|
|
+ fetchData();
|
|
|
+};
|
|
|
+
|
|
|
+const resetSearch = () => {
|
|
|
+ queryParam.value.requestIp = '';
|
|
|
+ queryParam.value.uid = '';
|
|
|
+ queryParam.value.ruleId = '';
|
|
|
+ queryParam.value.hostId = '';
|
|
|
+ queryParam.value.api = '';
|
|
|
+ queryParam.value.apiName = '';
|
|
|
+ queryParam.value.apiType = '';
|
|
|
+ queryParam.value.name = '';
|
|
|
+ handleSearch();
|
|
|
+};
|
|
|
+
|
|
|
+const detailModalRef = ref(null);
|
|
|
+
|
|
|
+const goToInfo = (id) => {
|
|
|
+ // 打开模态框而不是跳转页面
|
|
|
+ detailModalRef.value?.open(id);
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ fetchData();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.table-page-search-wrapper .ant-form-inline .ant-form-item {
|
|
|
+ margin-bottom: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格样式优化 */
|
|
|
+:deep(.ant-table-body) {
|
|
|
+ overflow-x: auto !important;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.ant-table-fixed-header .ant-table-scroll .ant-table-header) {
|
|
|
+ margin-bottom: 0 !important;
|
|
|
+ padding-bottom: 0 !important;
|
|
|
+ overflow: hidden !important;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.ant-table-body::-webkit-scrollbar) {
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.ant-table-body::-webkit-scrollbar-track) {
|
|
|
+ background: #f1f1f1;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.ant-table-body::-webkit-scrollbar-thumb) {
|
|
|
+ background: #c1c1c1;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.ant-table-body::-webkit-scrollbar-thumb:hover) {
|
|
|
+ background: #a8a8a8;
|
|
|
+}
|
|
|
+</style>
|