feat:优化攻击日志查询

This commit is contained in:
samwaf
2023-11-27 10:56:29 +08:00
parent fb58258507
commit 7bb8c59cd6
7 changed files with 539 additions and 423 deletions
+1 -1
View File
@@ -1 +1 @@
docker run --rm -v "$PWD":/media/sf_SamWaf -w /media/sf_SamWaf -e CGO_ENABLED=1 -e GOPROXY=https://goproxy.cn,direct golang:1.19 go build -v -ldflags="-X SamWaf/global.GWAF_RELEASE=true -X SamWaf/global.GWAF_RELEASE_VERSION_NAME=20231126 -X SamWaf/global.GWAF_RELEASE_VERSION=v1.0.125 -s -w -extldflags "-static"" -o /media/sf_SamWaf/release/SamWafLinux64 main.go
docker run --rm -v "$PWD":/media/sf_SamWaf -w /media/sf_SamWaf -e CGO_ENABLED=1 -e GOPROXY=https://goproxy.cn,direct golang:1.19 go build -v -ldflags="-X SamWaf/global.GWAF_RELEASE=true -X SamWaf/global.GWAF_RELEASE_VERSION_NAME=20231127 -X SamWaf/global.GWAF_RELEASE_VERSION=v1.0.126 -s -w -extldflags "-static"" -o /media/sf_SamWaf/release/SamWafLinux64 main.go
+79 -69
View File
@@ -61,74 +61,79 @@
wafanalysisdaycountryrange
} from '@/apis/stats';
echarts.use([TooltipComponent, LegendComponent, PieChart, GridComponent, LineChart, CanvasRenderer, MapChart, VisualMapComponent]);
import 'echarts-wordcloud';
import 'echarts-wordcloud';
export default {
name: 'Analysis',
data() {
return {
//词云的相关配置
wordCloudChartsInfo:{
wordCloudEchart:null,
wordCloudOptions:{
series: [{
type: 'wordCloud',
shape: 'circle',
keepAspect: false,
// maskImage: maskImage,
left: 'center',
top: 'center',
width: '100%',
height: '90%',
right: null,
bottom: null,
sizeRange: [12, 60],
rotationRange: [-90, 90],
rotationStep: 45,
gridSize: 8,
drawOutOfBound: false,
layoutAnimation: true,
wordCloudChartsInfo: {
wordCloudEchart: null,
wordCloudOptions: {
series: [{
type: 'wordCloud',
shape: 'circle',
keepAspect: false,
// maskImage: maskImage,
left: 'center',
top: 'center',
width: '100%',
height: '90%',
right: null,
bottom: null,
sizeRange: [12, 60],
rotationRange: [-90, 90],
rotationStep: 45,
gridSize: 8,
drawOutOfBound: false,
layoutAnimation: true,
textStyle: {
fontFamily: 'sans-serif',
fontWeight: 'bold',
color: function () {
return 'rgb(' + [
Math.round(Math.random() * 160),
Math.round(Math.random() * 160),
Math.round(Math.random() * 160)
].join(',') + ')';
}
},
emphasis: {
// focus: 'self',
textStyle: {
fontFamily: 'sans-serif',
fontWeight: 'bold',
color: function () {
return 'rgb(' + [
Math.round(Math.random() * 160),
Math.round(Math.random() * 160),
Math.round(Math.random() * 160)
].join(',') + ')';
}
},
emphasis: {
// focus: 'self',
textStyle: {
textShadowBlur: 3,
textShadowColor: '#333'
}
},
//data属性中的value值却大,权重就却大,展示字体就却大
data: [
//{name: 'Farrah',value: 366},
//{name: "汽车",value: 900},
//{name: "视频",value: 606},
]
textShadowBlur: 3,
textShadowColor: '#333'
}
},
//data属性中的value值却大,权重就却大,展示字体就却大
data: [
//{name: 'Farrah',value: 366},
//{name: "汽车",value: 900},
//{name: "视频",value: 606},
]
}]
}
}
},
currentAction: "",
action_options: [{
label: '阻止',
value: '阻止'
},
{
label: '放行',
value: '放行'
},
{
label: '禁止',
value: '禁止'
},
action_options: [
{
label: '全部',
value: ''
},
{
label: '阻止',
value: '阻止'
},
{
label: '放行',
value: '放行'
},
{
label: '禁止',
value: '禁止'
},
],
presets: {
最近7天: [new Date(+new Date() - 86400000 * 6), new Date()],
@@ -217,6 +222,11 @@ import 'echarts-wordcloud';
this.initEcharts();
this.loadCountryData();
},
created() {
this.range1[0] = LAST_7_DAYS[0]
this.range1[1] = LAST_7_DAYS[1]
console.log(this.range1)
},
methods: {
renderIcon() {
@@ -272,7 +282,7 @@ import 'echarts-wordcloud';
this.initWordCloud();
},
//初始化世界地图
initWorldMap(){
initWorldMap() {
//
/*
融合数据 世界和中国
@@ -313,16 +323,16 @@ import 'echarts-wordcloud';
}); */
},
//初始化词云
initWordCloud(){
let that = this
let echartDom = document.getElementById('wordCloudCountry')
that.wordCloudChartsInfo.wordCloudEchart = echarts.init(echartDom)
that.wordCloudChartsInfo.wordCloudEchart.setOption(that.wordCloudChartsInfo.wordCloudOptions)
initWordCloud() {
let that = this
let echartDom = document.getElementById('wordCloudCountry')
that.wordCloudChartsInfo.wordCloudEchart = echarts.init(echartDom)
that.wordCloudChartsInfo.wordCloudEchart.setOption(that.wordCloudChartsInfo.wordCloudOptions)
//随着屏幕大小调节图表
window.addEventListener("resize", () => {
that.wordCloudChartsInfo.wordCloudEchart.resize();
});
//随着屏幕大小调节图表
window.addEventListener("resize", () => {
that.wordCloudChartsInfo.wordCloudEchart.resize();
});
},
map_decodePolygon(coordinate, encodeOffsets, encodeScale) {
var result = [];
@@ -398,7 +408,7 @@ import 'echarts-wordcloud';
width: 80%;
height: 100vh;
/* 让布局占据整个视口高度 */
height:50rem;
height: 50rem;
}
.left-column {
@@ -434,4 +444,4 @@ import 'echarts-wordcloud';
/* 下半部分背景色 */
padding: 20px;
}
</style>
</style>
+434 -343
View File
@@ -3,21 +3,14 @@
<t-card class="list-card-container">
<t-row justify="space-between">
<t-form
ref="form"
:data="searchformData"
:label-width="80"
colon
:style="{ marginBottom: '8px' }"
>
<t-form ref="form" :data="searchformData" :label-width="80" colon :style="{ marginBottom: '8px' }">
<t-row>
<t-col :span="10">
<t-row :gutter="[16, 24]">
<t-col :flex="1">
<t-form-item label="网站" name="rule">
<t-select v-model="searchformData.host_code" clearable :style="{ width: '150px' }">
<t-option v-for="(item, index) in host_dic" :value="index" :label="item"
:key="index">
<t-option v-for="(item, index) in host_dic" :value="index" :label="item" :key="index">
{{ item }}
</t-option>
</t-select>
@@ -26,50 +19,43 @@
<t-col :flex="1">
<t-form-item label="规则名称" name="rule">
<t-input
v-model="searchformData.rule"
class="form-item-content"
type="search"
placeholder="请输入规则名称"
:style="{ minWidth: '134px' }"
/>
<t-input v-model="searchformData.rule" class="form-item-content" type="search" placeholder="请输入规则名称"
:style="{ minWidth: '134px' }" />
</t-form-item>
</t-col>
<t-col :flex="1">
<t-form-item label="访问状态" name="action">
<t-select
v-model="searchformData.action"
class="form-item-content`"
:options="action_options"
placeholder="请选择防御状态" :style="{ width: '100px' }"
/>
<t-select v-model="searchformData.action" class="form-item-content`" :options="action_options"
placeholder="请选择防御状态" :style="{ width: '100px' }" />
</t-form-item>
</t-col>
<t-col :flex="1">
<t-form-item label="响应码" name="status_code">
<t-input
v-model="searchformData.status_code"
class="form-item-content"
placeholder="请输入响应码"
:style="{ minWidth: '100px' }"
/>
<t-input v-model="searchformData.status_code" class="form-item-content" placeholder="请输入响应码"
:style="{ minWidth: '100px' }" />
</t-form-item>
</t-col>
<t-col :flex="1">
<t-form-item label="访问IP" name="src_ip">
<t-input
v-model="searchformData.src_ip"
class="form-item-content"
placeholder="请输入访问IP"
:style="{ minWidth: '100px' }"
/>
<t-input v-model="searchformData.src_ip" class="form-item-content" placeholder="请输入访问IP"
:style="{ minWidth: '100px' }" />
</t-form-item>
</t-col>
<t-col :flex="2">
<t-form-item label="访问日期" name="unix_add_time">
<t-date-range-picker v-model="range1" :presets="presets" enable-time-picker /></t-form-item>
</t-col>
<t-col :flex="1">
<t-form-item label="访问方法" name="method">
<t-select v-model="searchformData.method" class="form-item-content`" :options="method_options"
placeholder="请输入访问方法" :style="{ width: '100px' }" />
</t-form-item>
</t-col>
</t-row>
</t-col>
<t-col :span="2" class="operation-container">
<t-button theme="primary" :style="{ marginLeft: '8px' }" @click="getList('all')"> 查询 </t-button>
<t-button theme="primary" :style="{ marginLeft: '8px' }" @click="getList('all')"> 查询 </t-button>
<t-button type="reset" variant="base" theme="default"> 重置 </t-button>
</t-col>
</t-row>
@@ -77,365 +63,470 @@
</t-row>
<div class="table-container">
<t-table
:columns="columns"
:data="data"
size="small"
:rowKey="rowKey"
:verticalAlign="verticalAlign"
:pagination="pagination"
:selected-row-keys="selectedRowKeys"
:loading="dataLoading"
@page-change="rehandlePageChange"
@change="rehandleChange"
@select-change="rehandleSelectChange"
:headerAffixProps="{ offsetTop: offsetTop, container: getContainer }"
>
<!-- 按钮操作区域 -->
<!-- <t-space direction="vertical">
<t-space>
<t-checkbox v-model="customText" style="margin-left: 16px">自定义列配置按钮</t-checkbox>
</t-space>
</t-space> -->
<t-table :columns="columns" :data="data" size="small" :rowKey="rowKey" :verticalAlign="verticalAlign"
:column-controller="columnControllerConfig" :displayColumns.sync="displayColumns" :pagination="pagination"
:selected-row-keys="selectedRowKeys" :loading="dataLoading" @page-change="rehandlePageChange"
@change="rehandleChange" @select-change="rehandleSelectChange"
:headerAffixProps="{ offsetTop: offsetTop, container: getContainer }">
<template #action="{ row }">
<t-tag v-if="row.action === '放行'" shape="round" theme="success" >{{row.action}}</t-tag>
<t-tag v-if="row.action === '阻止'" shape="round" theme="danger" >{{row.action}}</t-tag>
<t-tag v-if="row.action === '禁止'" shape="round" theme="warning" >{{row.action}}</t-tag>
<template #action="{ row }">
<t-tag v-if="row.action === '放行'" shape="round" theme="success">{{row.action}}</t-tag>
<t-tag v-if="row.action === '阻止'" shape="round" theme="danger">{{row.action}}</t-tag>
<t-tag v-if="row.action === '禁止'" shape="round" theme="warning">{{row.action}}</t-tag>
</template>
<template #rule="{ row }">
<t-tag v-if="row.rule !== ''" shape="round" theme="primary" variant="outline">{{row.rule}}</t-tag>
</template>
<template #country="{ row }">
{{row.src_ip }} ({{row.country }}{{row.province }}{{row.city }})
</template>
<t-tag v-if="row.rule !== ''" shape="round" theme="primary" variant="outline">{{row.rule}}</t-tag>
</template>
<template #op="slotProps">
<a class="t-button-link" @click="handleClickIPDetail(slotProps)">查询IP</a>
<a class="t-button-link" @click="handleClickDetail(slotProps)">详情</a>
<a class="t-button-link" @click="handleClickDelete(slotProps)">删除</a>
<!-- <a class="t-button-link" @click="handleClickDelete(slotProps)">删除</a> -->
</template>
</t-table>
</div>
</t-card>
<t-dialog
header="确认删除当前所选合同?"
:body="confirmBody"
:visible.sync="confirmVisible"
@confirm="onConfirmDelete"
:onCancel="onCancel"
>
<t-dialog header="确认删除当前所选日志?" :body="confirmBody" :visible.sync="confirmVisible" @confirm="onConfirmDelete"
:onCancel="onCancel">
</t-dialog>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { SearchIcon } from 'tdesign-icons-vue';
import Trend from '@/components/trend/index.vue';
import { prefix } from '@/config/global';
import {attacklogList} from '@/apis/waflog/attacklog';
import Vue from 'vue';
import { SearchIcon } from 'tdesign-icons-vue';
import Trend from '@/components/trend/index.vue';
import { prefix } from '@/config/global';
import { attacklogList } from '@/apis/waflog/attacklog';
import { NowDate, ConvertStringToUnix, ConvertDateToString } from '@/utils/date';
import {
allhost
} from '@/apis/host';
import { CONTRACT_STATUS, CONTRACT_STATUS_OPTIONS, CONTRACT_TYPES, CONTRACT_PAYMENT_TYPES } from '@/constants';
import { ErrorCircleFilledIcon, CheckCircleFilledIcon, CloseCircleFilledIcon } from 'tdesign-icons-vue';
import { CONTRACT_STATUS, CONTRACT_STATUS_OPTIONS, CONTRACT_TYPES, CONTRACT_PAYMENT_TYPES } from '@/constants';
import { ErrorCircleFilledIcon, CheckCircleFilledIcon, CloseCircleFilledIcon } from 'tdesign-icons-vue';
export default Vue.extend({
name: 'ListBase',
components: {
SearchIcon,
Trend,
},
data() {
return {
action_options: [{
label: '阻止',
value: '阻止'
},
{
label: '放行',
value: '放行'
},
{
label: '禁止',
value: '禁止'
},
],
CONTRACT_STATUS,
CONTRACT_STATUS_OPTIONS,
CONTRACT_TYPES,
CONTRACT_PAYMENT_TYPES,
prefix,
dataLoading: false,
data: [],
selectedRowKeys: [],
value: 'first',
columns: [
{
title: '状态',
width: 60,
ellipsis: true,
colKey: 'action',
},
{
title: '触发规则',
align: 'left',
width: 150,
ellipsis: true,
colKey: 'rule',
},
{
title: '时间',
width: 170,
ellipsis: true,
colKey: 'create_time',
},
{
title: '域名',
align: 'left',
width: 150,
ellipsis: true,
colKey: 'host',
},
const staticColumn = ['action', 'op'];
{
title: '请求',
width: 70,
ellipsis: true,
colKey: 'method',
},
{
title: '来源IP',
width: 150,
ellipsis: true,
colKey: 'country',
},
{
title: '访问url',
width: 300,
ellipsis: true,
colKey: 'url',
},
{
align: 'left',
width: 200,
colKey: 'op',
title: '操作',
},
],
rowKey: 'REQ_UUID',
tableLayout: 'auto',
verticalAlign: 'top',
hover: true,
rowClassName: (rowKey: string) => `${rowKey}-class`,
// 与pagination对齐
pagination: {
total: 0,
current: 1,
pageSize:10
},
searchValue: '',
confirmVisible: false,
deleteIdx: -1,
//顶部搜索
searchformData:{
rule:"",
action:"",
src_ip:"",
host_code:"",
status_code:""
},
//主机字典
host_dic:{}
};
},
computed: {
confirmBody() {
if (this.deleteIdx > -1) {
const { name } = this.data?.[this.deleteIdx];
return `删除后,${name}的所有合同信息将被清空,且无法恢复`;
}
return '';
const GROUP_COLUMNS = [
{
label: '正常维度',
value: 'index',
columns: ['action', 'rule', 'create_time'],
},
offsetTop() {
return this.$store.state.setting.isUseTabsRouter ? 48 : 0;
{
label: '次要维度',
value: 'secondary',
columns: ['action', 'rule', 'create_time'],
},
},
mounted() {
console.log("attack list mounted ");
if(this.$route.query.action != null){
{
label: '数据维度',
value: 'data',
columns: ['action', 'rule', 'create_time'],
},
];
export default Vue.extend({
name: 'ListBase',
components: {
SearchIcon,
Trend,
},
data() {
return {
presets: {
最近300天: [ConvertDateToString(new Date(+new Date() - 86400000 * 299)) + " 00:00:00", ConvertDateToString(new Date()) + " 23:59:59"],
最近7天: [ConvertDateToString(new Date(+new Date() - 86400000 * 6)) + " 00:00:00", ConvertDateToString(new Date()) + " 23:59:59"],
最近3天: [ConvertDateToString(new Date(+new Date() - 86400000 * 2)) + " 00:00:00", ConvertDateToString(new Date()) + " 23:59:59"],
今天: [ConvertDateToString(new Date()) + " 00:00:00", ConvertDateToString(new Date()) + " 23:59:59"],
},
range1: ['2023-11-01 00:00:00', '2023-11-16 23:59:59'],
action_options: [
{
label: '全部',
value: ''
},
{
label: '阻止',
value: '阻止'
},
{
label: '放行',
value: '放行'
},
{
label: '禁止',
value: '禁止'
},
],
method_options: [
{
label: '全部',
value: ''
},
{
label: 'POST',
value: 'POST'
},
{
label: 'GET',
value: 'GET'
},
{
label: 'CONNECT',
value: 'CONNECT'
}
,
{
label: 'HEAD',
value: 'HEAD'
},
{
label: 'OPTIONS',
value: 'OPTIONS'
},
{
label: 'PRI',
value: 'PRI'
}
],
CONTRACT_STATUS,
CONTRACT_STATUS_OPTIONS,
CONTRACT_TYPES,
CONTRACT_PAYMENT_TYPES,
prefix,
dataLoading: false,
data: [],
selectedRowKeys: [],
value: 'first',
customText: false,
displayColumns: staticColumn.concat(['create_time','host','method','url','src_ip','country']),
columns: [
{
title: '状态',
width: 60,
ellipsis: true,
colKey: 'action',
},
{
title: '触发规则',
align: 'left',
width: 150,
ellipsis: true,
colKey: 'rule',
},
{
title: '时间',
width: 170,
ellipsis: true,
colKey: 'create_time',
},
{
title: '域名',
align: 'left',
width: 150,
ellipsis: true,
colKey: 'host',
},
{
title: '请求',
width: 70,
ellipsis: true,
colKey: 'method',
},
{
title: '来源IP',
width: 150,
ellipsis: true,
colKey: 'src_ip',
},
{
title: '国家',
width: 100,
ellipsis: true,
colKey: 'country',
},
{
title: '省份',
width: 100,
ellipsis: true,
colKey: 'province',
},{
title: '城市',
width: 100,
ellipsis: true,
colKey: 'city',
},
{
title: '访问url',
width: 300,
ellipsis: true,
colKey: 'url',
},
{
title: 'Header',
width: 300,
ellipsis: true,
colKey: 'header',
},
{
title: 'status',
width: 100,
ellipsis: true,
colKey: 'status',
},
{
align: 'left',
width: 200,
colKey: 'op',
title: '操作',
},
],
rowKey: 'REQ_UUID',
tableLayout: 'auto',
verticalAlign: 'top',
hover: true,
rowClassName: (rowKey : string) => `${rowKey}-class`,
// 与pagination对齐
pagination: {
total: 0,
current: 1,
pageSize: 10
},
searchValue: '',
confirmVisible: false,
deleteIdx: -1,
//顶部搜索
searchformData: {
rule: "",
action: "",
src_ip: "",
host_code: "",
status_code: "",
method: "",
},
//主机字典
host_dic: {}
};
},
computed: {
confirmBody() {
if (this.deleteIdx > -1) {
const { name } = this.data?.[this.deleteIdx];
return `删除后,${name}的所有合同信息将被清空,且无法恢复`;
}
return '';
},
offsetTop() {
return this.$store.state.setting.isUseTabsRouter ? 48 : 0;
},
columnControllerConfig() {
return {
placement: this.placement,
fields: ['action', 'rule', 'create_time', 'host', 'method', 'url', 'header','country','province','city','status'],
// 弹框组件属性透传
dialogProps: { preventScrollThrough: true },
// 列配置按钮属性头像
buttonProps: this.customText ? { content: '显示列控制', theme: 'primary', variant: 'base' } : undefined,
// 数据字段分组显示
groupColumns: this.groupColumn ? GROUP_COLUMNS : undefined,
};
},
},
created() {
console.log(NowDate)
this.range1[0] = NowDate + " 00:00:00"
this.range1[1] = NowDate + " 23:59:59"
console.log(this.range1)
},
mounted() {
console.log("attack list mounted ");
if (this.$route.query.action != null) {
console.log(this.$route.query.action)
this.searchformData.action = this.$route.query.action
}
// 判断 vuex 中是否有保存的搜索参数
}
// 判断 vuex 中是否有保存的搜索参数
if (this.$store.state.attacklog.msgData) {
const attack = this.$store.state.attacklog;
this.pagination.current = attack.msgData.currentpage;
this.searchformData = attack.msgData.searchData; // 可以直接取出整个对象
}
if (this.$store.state.attacklog.msgData) {
const attack = this.$store.state.attacklog;
this.pagination.current = attack.msgData.currentpage;
this.searchformData = attack.msgData.searchData; // 可以直接取出整个对象
}
this.loadHostList()
this.getList("")
},
watch: {
'$route.query.action'(newVal, oldVal) {
console.log('action changed', newVal, oldVal)
this.searchformData.action = newVal
this.loadHostList()
this.getList("")
},
},
beforeRouteLeave(to, from, next) {
console.log("attack list beforeRouteLeave ");
// vuex 存储操作
this.$store.dispatch("attacklog/setAttackMsgData", {
//query: this.queryParam,
currentpage: this.pagination.current,
searchData: this.searchformData,
})
next();   // 继续后续的导航解析过程
},
methods: {
loadHostList(){
let that = this;
allhost().then((res) => {
let resdata = res
console.log(resdata)
if (resdata.code === 0) {
let host_options = resdata.data;
for(let i = 0;i<host_options.length;i++){
that.host_dic[host_options[i].value] = host_options[i].label
}
}
})
.catch((e: Error) => {
console.log(e);
})
watch: {
'$route.query.action'(newVal, oldVal) {
console.log('action changed', newVal, oldVal)
this.searchformData.action = newVal
this.getList("")
},
},
getList(keyword){
let that = this
if(keyword!=undefined && keyword=="all"){
that.pagination.current = 1
}
this.$request
.post('/waflog/attack/list', {
pageSize: that.pagination.pageSize,
pageIndex: that.pagination.current,
...that.searchformData
},
)
.then((res) => {
beforeRouteLeave(to, from, next) {
console.log("attack list beforeRouteLeave ");
// vuex 存储操作
this.$store.dispatch("attacklog/setAttackMsgData", {
//query: this.queryParam,
currentpage: this.pagination.current,
searchData: this.searchformData,
})
next();   // 继续后续的导航解析过程
},
methods: {
loadHostList() {
let that = this;
allhost().then((res) => {
let resdata = res
console.log(resdata)
if (resdata.code === 0) {
//const { list = [] } = resdata.data.list;
this.data = resdata.data.list;
this.pagination = {
...this.pagination,
total: resdata.data.total,
};
let host_options = resdata.data;
for (let i = 0; i < host_options.length; i++) {
that.host_dic[host_options[i].value] = host_options[i].label
}
}
})
.catch((e: Error) => {
console.log(e);
})
.finally(() => {
this.dataLoading = false;
});
this.dataLoading = true;
},
getContainer() {
return document.querySelector('.tdesign-starter-layout');
},
rehandlePageChange(curr, pageInfo) {
console.log('分页变化', curr, pageInfo);
this.pagination.current = curr.current
if(this.pagination.pageSize != curr.pageSize){
.catch((e : Error) => {
console.log(e);
})
},
getList(keyword) {
let that = this
if (keyword != undefined && keyword == "all") {
that.pagination.current = 1
}
this.$request
.post('/waflog/attack/list', {
pageSize: that.pagination.pageSize,
pageIndex: that.pagination.current,
unix_add_time_begin: ConvertStringToUnix(this.range1[0]).toString(),
unix_add_time_end: ConvertStringToUnix(this.range1[1]).toString(),
...that.searchformData
},
)
.then((res) => {
let resdata = res
console.log(resdata)
if (resdata.code === 0) {
//const { list = [] } = resdata.data.list;
this.data = resdata.data.list;
this.pagination = {
...this.pagination,
total: resdata.data.total,
};
}
})
.catch((e : Error) => {
console.log(e);
})
.finally(() => {
this.dataLoading = false;
});
this.dataLoading = true;
},
getContainer() {
return document.querySelector('.tdesign-starter-layout');
},
rehandlePageChange(curr, pageInfo) {
console.log('分页变化', curr, pageInfo);
this.pagination.current = curr.current
if (this.pagination.pageSize != curr.pageSize) {
this.pagination.current = 1
this.pagination.pageSize = curr.pageSize
}
this.getList("")
},
rehandleSelectChange(selectedRowKeys: number[]) {
this.selectedRowKeys = selectedRowKeys;
},
rehandleChange(changeParams, triggerAndData) {
console.log('统一Change', changeParams, triggerAndData);
},
handleClickDetail(e) {
console.log(e)
const { req_uuid } = e.row
console.log(req_uuid)
this.$router.push(
{
path:'/waf/wafattacklogdetail',
query: {
req_uuid: req_uuid,
},
}
this.getList("")
},
);
},
handleClickIPDetail(e) {
console.log(e)
const { src_ip } = e.row
this.searchformData.src_ip = src_ip
this.getList("")
rehandleSelectChange(selectedRowKeys : number[]) {
this.selectedRowKeys = selectedRowKeys;
},
rehandleChange(changeParams, triggerAndData) {
console.log('统一Change', changeParams, triggerAndData);
},
handleClickDetail(e) {
console.log(e)
const { req_uuid } = e.row
console.log(req_uuid)
this.$router.push(
{
path: '/waf/wafattacklogdetail',
query: {
req_uuid: req_uuid,
},
},
);
},
handleClickIPDetail(e) {
console.log(e)
const { src_ip } = e.row
this.searchformData.src_ip = src_ip
this.getList("")
},
handleClickDelete(row : { rowIndex : any }) {
this.deleteIdx = row.rowIndex;
this.confirmVisible = true;
},
onConfirmDelete() {
// 真实业务请发起请求
this.data.splice(this.deleteIdx, 1);
this.pagination.total = this.data.length;
const selectedIdx = this.selectedRowKeys.indexOf(this.deleteIdx);
if (selectedIdx > -1) {
this.selectedRowKeys.splice(selectedIdx, 1);
}
this.confirmVisible = false;
this.$message.success('删除成功');
this.resetIdx();
},
onCancel() {
this.resetIdx();
},
resetIdx() {
this.deleteIdx = -1;
},
},
handleClickDelete(row: { rowIndex: any }) {
this.deleteIdx = row.rowIndex;
this.confirmVisible = true;
},
onConfirmDelete() {
// 真实业务请发起请求
this.data.splice(this.deleteIdx, 1);
this.pagination.total = this.data.length;
const selectedIdx = this.selectedRowKeys.indexOf(this.deleteIdx);
if (selectedIdx > -1) {
this.selectedRowKeys.splice(selectedIdx, 1);
}
this.confirmVisible = false;
this.$message.success('删除成功');
this.resetIdx();
},
onCancel() {
this.resetIdx();
},
resetIdx() {
this.deleteIdx = -1;
},
},
});
});
</script>
<style lang="less" scoped>
@import '@/style/variables';
@import '@/style/variables';
.payment-col {
display: flex;
.trend-container {
.payment-col {
display: flex;
align-items: center;
margin-left: 8px;
.trend-container {
display: flex;
align-items: center;
margin-left: 8px;
}
}
}
.left-operation-container {
padding: 0 0 6px 0;
margin-bottom: 16px;
.left-operation-container {
padding: 0 0 6px 0;
margin-bottom: 16px;
.selected-count {
display: inline-block;
margin-left: 8px;
color: var(--td-text-color-secondary);
.selected-count {
display: inline-block;
margin-left: 8px;
color: var(--td-text-color-secondary);
}
}
}
.search-input {
width: 360px;
}
.search-input {
width: 360px;
}
.t-button + .t-button {
.t-button+.t-button {
margin-left: @spacer;
}
}
</style>
+12 -1
View File
@@ -5,9 +5,20 @@ export const LAST_7_DAYS = [
dayjs().subtract(7, 'day').format('YYYY-MM-DD'),
dayjs().format('YYYY-MM-DD'),
];
export const LAST_30_DAYS = [
dayjs().subtract(30, 'day').format('YYYY-MM-DD'),
dayjs().subtract(1, 'day').format('YYYY-MM-DD'),
];
//当前日期
export const NowDate = dayjs().format('YYYY-MM-DD');
//转换数据成毫秒
export function ConvertStringToUnix(timestr: string) :Number{
return dayjs(timestr).valueOf()
}
//转换字符串
export function ConvertDateToString(now: Date) :string{
return dayjs(now).format('YYYY-MM-DD');
}
+8 -5
View File
@@ -3,10 +3,13 @@ package request
import "SamWaf/model/common/request"
type WafAttackLogSearch struct {
HostCode string `json:"host_code" form:"host_code"` //主机码
Rule string `json:"rule" form:"rule"` //规则名
Action string `json:"action" form:"action"` //状态
SrcIp string `json:"src_ip" form:"src_ip"` //请求IP
StatusCode string `json:"status_code" form:"status_code"` //响应码
HostCode string `json:"host_code" form:"host_code"` //主机码
Rule string `json:"rule" form:"rule"` //规则名
Action string `json:"action" form:"action"` //状态
SrcIp string `json:"src_ip" form:"src_ip"` //请求IP
StatusCode string `json:"status_code" form:"status_code"` //响应码
UnixAddTimeBegin string `json:"unix_add_time_begin" form:"unix_add_time_begin"` //开始时间
UnixAddTimeEnd string `json:"unix_add_time_end" form:"unix_add_time_end"` //结束时间
Method string `json:"method" form:"method"` //访问方法
request.PageInfo
}
+3 -2
View File
@@ -34,14 +34,15 @@ func (receiver *WafLogService) GetListApi(log request.WafAttackLogSearch) ([]inn
Action: log.Action,
SrcIp: log.SrcIp,
StatusCode: log.StatusCode,
Method: log.Method,
PageInfo: request2.PageInfo{
PageIndex: 0,
PageSize: 0,
Keyword: "",
},
}
global.GWAF_LOCAL_LOG_DB.Limit(log.PageSize).Where(whereCondition).Offset(log.PageSize * (log.PageIndex - 1)).Order("create_time desc").Find(&weblogs)
global.GWAF_LOCAL_LOG_DB.Model(&innerbean.WebLog{}).Where(whereCondition).Count(&total)
global.GWAF_LOCAL_LOG_DB.Limit(log.PageSize).Where(whereCondition).Where("unix_add_time>=? and unix_add_time<=?", log.UnixAddTimeBegin, log.UnixAddTimeEnd).Offset(log.PageSize * (log.PageIndex - 1)).Order("create_time desc").Find(&weblogs)
global.GWAF_LOCAL_LOG_DB.Model(&innerbean.WebLog{}).Where(whereCondition).Where("unix_add_time>=? and unix_add_time<=?", log.UnixAddTimeBegin, log.UnixAddTimeEnd).Count(&total)
return weblogs, total, nil
}
func (receiver *WafLogService) GetListByHostCodeApi(log request.WafAttackLogSearch) ([]innerbean.WebLog, int64, error) {
+2 -2
View File
@@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sam网站应用级入侵防御系统后台(Web Application Firewall)</title>
<script type="module" crossorigin src="./assets/index.3ebd5785.js"></script>
<link rel="stylesheet" href="./assets/style.caefab01.css">
<script type="module" crossorigin src="./assets/index.bdd9c8b0.js"></script>
<link rel="stylesheet" href="./assets/style.2e845f6b.css">
</head>
<body>
<div id="app"></div>