feat: SSH 日志统计信息增加分页 (#2509)

pull/2510/head
ssongliu 1 year ago committed by GitHub
parent faf4174adf
commit c01b3764f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -38,9 +38,17 @@ type SSHLog struct {
}
type SearchForAnalysis struct {
PageInfo
OrderBy string `json:"orderBy" validate:"required,oneof=Success Failed"`
}
type AnalysisRes struct {
Total int64 `json:"total"`
Items []SSHLogAnalysis `json:"items"`
SuccessfulCount int `json:"successfulCount"`
FailedCount int `json:"failedCount"`
}
type SSHLogAnalysis struct {
Address string `json:"address"`
Area string `json:"area"`

@ -32,7 +32,7 @@ type ISSHService interface {
UpdateByFile(value string) error
Update(key, value string) error
GenerateSSH(req dto.GenerateSSH) error
AnalysisLog(req dto.SearchForAnalysis) ([]dto.SSHLogAnalysis, error)
AnalysisLog(req dto.SearchForAnalysis) (*dto.AnalysisRes, error)
LoadSSHSecret(mode string) (string, error)
LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error)
@ -304,7 +304,7 @@ func (u *SSHService) LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error) {
return &data, nil
}
func (u *SSHService) AnalysisLog(req dto.SearchForAnalysis) ([]dto.SSHLogAnalysis, error) {
func (u *SSHService) AnalysisLog(req dto.SearchForAnalysis) (*dto.AnalysisRes, error) {
var fileList []string
baseDir := "/var/log"
if err := filepath.Walk(baseDir, func(pathItem string, info os.FileInfo, err error) error {
@ -365,7 +365,26 @@ func (u *SSHService) AnalysisLog(req dto.SearchForAnalysis) ([]dto.SSHLogAnalysi
}
}
return sortSlice, nil
var backData dto.AnalysisRes
for _, item := range sortSlice {
backData.FailedCount += item.FailedCount
backData.SuccessfulCount += item.SuccessfulCount
}
var data []dto.SSHLogAnalysis
total, start, end := len(sortSlice), (req.Page-1)*req.PageSize, req.Page*req.PageSize
if start > total {
data = make([]dto.SSHLogAnalysis, 0)
} else {
if end >= total {
end = total
}
data = sortSlice[start:end]
}
backData.Items = data
backData.Total = int64(total)
return &backData, nil
}
func (u *SSHService) LoadSSHConf() (string, error) {

@ -1,5 +1,5 @@
// Package docs GENERATED BY SWAG; DO NOT EDIT
// This file was generated by swaggo/swag
// Code generated by swaggo/swag. DO NOT EDIT.
package docs
import "github.com/swaggo/swag"
@ -7950,7 +7950,7 @@ const docTemplate = `{
"ApiKeyAuth": []
}
],
"description": "操作 Node 项目 modules",
"description": "操作 Node 项目 modules",
"consumes": [
"application/json"
],
@ -14917,7 +14917,9 @@ const docTemplate = `{
"dto.SearchForAnalysis": {
"type": "object",
"required": [
"orderBy"
"orderBy",
"page",
"pageSize"
],
"properties": {
"orderBy": {
@ -14926,6 +14928,12 @@ const docTemplate = `{
"Success",
"Failed"
]
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
}
}
},
@ -16730,24 +16738,6 @@ const docTemplate = `{
"properties": {
"ID": {
"type": "integer"
},
"module": {
"type": "string"
},
"operate": {
"type": "string",
"enum": [
"install",
"uninstall",
"update"
]
},
"pkgManager": {
"type": "string",
"enum": [
"npm",
"yarn"
]
}
}
},

@ -7943,7 +7943,7 @@
"ApiKeyAuth": []
}
],
"description": "操作 Node 项目 modules",
"description": "操作 Node 项目 modules",
"consumes": [
"application/json"
],
@ -14910,7 +14910,9 @@
"dto.SearchForAnalysis": {
"type": "object",
"required": [
"orderBy"
"orderBy",
"page",
"pageSize"
],
"properties": {
"orderBy": {
@ -14919,6 +14921,12 @@
"Success",
"Failed"
]
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
}
}
},
@ -16723,24 +16731,6 @@
"properties": {
"ID": {
"type": "integer"
},
"module": {
"type": "string"
},
"operate": {
"type": "string",
"enum": [
"install",
"uninstall",
"update"
]
},
"pkgManager": {
"type": "string",
"enum": [
"npm",
"yarn"
]
}
}
},

@ -1931,8 +1931,14 @@ definitions:
- Success
- Failed
type: string
page:
type: integer
pageSize:
type: integer
required:
- orderBy
- page
- pageSize
type: object
dto.SearchForTree:
properties:
@ -3135,19 +3141,6 @@ definitions:
properties:
ID:
type: integer
module:
type: string
operate:
enum:
- install
- uninstall
- update
type: string
pkgManager:
enum:
- npm
- yarn
type: string
required:
- ID
type: object
@ -9207,7 +9200,7 @@ paths:
post:
consumes:
- application/json
description: 操作 Node 项目 modules
description: 操作 Node 项目 modules
parameters:
- description: request
in: body

@ -136,6 +136,15 @@ export namespace Host {
info: string;
status: string;
}
export interface analysisSSHLog extends ReqPage {
orderBy: string;
}
export interface logAnalysisRes {
total: number;
items: Array<logAnalysis>;
successfulCount: number;
failedCount: number;
}
export interface sshLog {
logs: Array<sshHistory>;
successfulCount: number;

@ -123,6 +123,6 @@ export const loadSecret = (mode: string) => {
export const loadSSHLogs = (params: Host.searchSSHLog) => {
return http.post<Host.sshLog>(`/hosts/ssh/log`, params);
};
export const loadAnalysis = (orderBy: string) => {
return http.post<Array<Host.logAnalysis>>(`/hosts/ssh/log/analysis`, { orderBy: orderBy }, TimeoutEnum.T_40S);
export const loadAnalysis = (params: Host.analysisSSHLog) => {
return http.post<Host.logAnalysisRes>(`/hosts/ssh/log/analysis`, params, TimeoutEnum.T_40S);
};

@ -32,14 +32,16 @@
<el-button type="primary" @click="onChangeStatus('drop', null)" :disabled="selects.length === 0">
{{ $t('firewall.deny') }}
</el-button>
<ComplexTable v-model:selects="selects" class="mt-5" :data="data" @header-click="changeSort">
<el-table v-model:selects="selects" class="mt-5" :data="data" @header-click="changeSort">
<el-table-column type="selection" fix :selectable="selectable" />
<el-table-column :label="$t('logs.loginIP')" prop="address" min-width="40" />
<el-table-column :label="$t('ssh.belong')" prop="area" min-width="40" />
<el-table-column prop="successfulCount" min-width="20">
<template #header>
{{ $t('ssh.successful') }}
<el-icon style="cursor: pointer" @click="search('Success')"><CaretBottom /></el-icon>
<el-icon style="cursor: pointer" @click="(orderBy = 'Success') && search()">
<CaretBottom />
</el-icon>
</template>
<template #default="{ row }">
<el-button type="primary" link>{{ row.successfulCount }}</el-button>
@ -48,7 +50,9 @@
<el-table-column prop="failedCount" min-width="20">
<template #header>
{{ $t('ssh.failed') }}
<el-icon style="cursor: pointer" @click="search('Failed')"><CaretBottom /></el-icon>
<el-icon style="cursor: pointer" @click="(orderBy = 'Failed') && search()">
<CaretBottom />
</el-icon>
</template>
<template #default="{ row }">
<el-button type="danger" link>{{ row.failedCount }}</el-button>
@ -76,7 +80,15 @@
</el-button>
</template>
</el-table-column>
</ComplexTable>
</el-table>
<fu-table-pagination
class="float-right mt-4"
v-model:current-page="paginationConfig.currentPage"
v-model:page-size="paginationConfig.pageSize"
v-bind="paginationConfig"
@change="search()"
:layout="'prev, pager, next'"
/>
</div>
<template #footer>
<span class="dialog-footer">
@ -120,7 +132,7 @@
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { reactive, ref } from 'vue';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { loadAnalysis, operateIPRule } from '@/api/modules/host';
import { MsgError, MsgSuccess } from '@/utils/message';
@ -133,29 +145,38 @@ const data = ref();
const successfulTotalCount = ref();
const failedTotalCount = ref();
const selects = ref<any>([]);
const orderBy = ref<string>('Failed');
const dialogVisible = ref();
const msg = ref();
const operation = ref();
const operationList = ref();
const paginationConfig = reactive({
currentPage: 1,
pageSize: 10,
total: 0,
});
const acceptParams = (): void => {
search('Failed');
search();
drawerVisible.value = true;
};
const search = async (status: string) => {
const search = async () => {
let params = {
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
orderBy: orderBy.value,
};
loading.value = true;
loadAnalysis(status)
loadAnalysis(params)
.then((res) => {
loading.value = false;
data.value = res.data || [];
successfulTotalCount.value = 0;
failedTotalCount.value = 0;
for (const item of data.value) {
successfulTotalCount.value += item.successfulCount;
failedTotalCount.value += item.failedCount;
}
data.value = res.data.items || [];
successfulTotalCount.value = res.data.successfulCount;
failedTotalCount.value = res.data.failedCount;
paginationConfig.total = res.data.total;
})
.catch(() => {
loading.value = false;
@ -169,10 +190,12 @@ function selectable(row: any): boolean {
const changeSort = (column: any) => {
switch (column.property) {
case 'successfulCount':
search('Success');
orderBy.value = 'Success';
search();
return;
case 'failedCount':
search('Failed');
orderBy.value = 'Failed';
search();
return;
}
};
@ -218,7 +241,7 @@ const submitOperation = async () => {
.then(() => {
loading.value = false;
dialogVisible.value = false;
search('Failed');
search();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.finally(() => {

Loading…
Cancel
Save