mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-10 04:16:29 +08:00
fix: 优化病毒扫描报告界面 (#5675)
This commit is contained in:
parent
a4accc071d
commit
f370f7eacf
15 changed files with 267 additions and 42 deletions
|
|
@ -163,6 +163,29 @@ func (b *BaseApi) SearchClamRecord(c *gin.Context) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Clam
|
||||||
|
// @Summary Load clam record detail
|
||||||
|
// @Description 获取扫描结果详情
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.ClamLogReq true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /toolbox/clam/record/log [post]
|
||||||
|
func (b *BaseApi) LoadClamRecordLog(c *gin.Context) {
|
||||||
|
var req dto.ClamLogReq
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := clamService.LoadRecordLog(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, content)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Clam
|
// @Tags Clam
|
||||||
// @Summary Load clam file
|
// @Summary Load clam file
|
||||||
// @Description 获取扫描文件
|
// @Description 获取扫描文件
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,18 @@ type ClamLogSearch struct {
|
||||||
EndTime time.Time `json:"endTime"`
|
EndTime time.Time `json:"endTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ClamLogReq struct {
|
||||||
|
Tail string `json:"tail"`
|
||||||
|
ClamName string `json:"clamName"`
|
||||||
|
RecordName string `json:"recordName"`
|
||||||
|
}
|
||||||
|
|
||||||
type ClamLog struct {
|
type ClamLog struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ScanDate string `json:"scanDate"`
|
ScanDate string `json:"scanDate"`
|
||||||
ScanTime string `json:"scanTime"`
|
ScanTime string `json:"scanTime"`
|
||||||
InfectedFiles string `json:"infectedFiles"`
|
InfectedFiles string `json:"infectedFiles"`
|
||||||
Log string `json:"log"`
|
TotalError string `json:"totalError"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,7 +64,7 @@ type ClamUpdate struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClamDelete struct {
|
type ClamDelete struct {
|
||||||
RemoveResult bool `json:"removeResult"`
|
RemoveRecord bool `json:"removeRecord"`
|
||||||
RemoveInfected bool `json:"removeInfected"`
|
RemoveInfected bool `json:"removeInfected"`
|
||||||
Ids []uint `json:"ids" validate:"required"`
|
Ids []uint `json:"ids" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ type IClamService interface {
|
||||||
UpdateFile(req dto.UpdateByNameAndFile) error
|
UpdateFile(req dto.UpdateByNameAndFile) error
|
||||||
LoadRecords(req dto.ClamLogSearch) (int64, interface{}, error)
|
LoadRecords(req dto.ClamLogSearch) (int64, interface{}, error)
|
||||||
CleanRecord(req dto.OperateByID) error
|
CleanRecord(req dto.OperateByID) error
|
||||||
|
|
||||||
|
LoadRecordLog(req dto.ClamLogReq) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIClamService() IClamService {
|
func NewIClamService() IClamService {
|
||||||
|
|
@ -160,7 +162,7 @@ func (u *ClamService) Delete(req dto.ClamDelete) error {
|
||||||
if clam.ID == 0 {
|
if clam.ID == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if req.RemoveResult {
|
if req.RemoveRecord {
|
||||||
_ = os.RemoveAll(path.Join(global.CONF.System.DataDir, resultDir, clam.Name))
|
_ = os.RemoveAll(path.Join(global.CONF.System.DataDir, resultDir, clam.Name))
|
||||||
}
|
}
|
||||||
if req.RemoveInfected {
|
if req.RemoveInfected {
|
||||||
|
|
@ -255,6 +257,21 @@ func (u *ClamService) LoadRecords(req dto.ClamLogSearch) (int64, interface{}, er
|
||||||
}
|
}
|
||||||
return int64(total), datas, nil
|
return int64(total), datas, nil
|
||||||
}
|
}
|
||||||
|
func (u *ClamService) LoadRecordLog(req dto.ClamLogReq) (string, error) {
|
||||||
|
logPath := path.Join(global.CONF.System.DataDir, resultDir, req.ClamName, req.RecordName)
|
||||||
|
var tail string
|
||||||
|
if req.Tail != "0" {
|
||||||
|
tail = req.Tail
|
||||||
|
} else {
|
||||||
|
tail = "+1"
|
||||||
|
}
|
||||||
|
cmd := exec.Command("tail", "-n", tail, logPath)
|
||||||
|
stdout, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("tail -n %v failed, err: %v", req.Tail, err)
|
||||||
|
}
|
||||||
|
return string(stdout), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *ClamService) CleanRecord(req dto.OperateByID) error {
|
func (u *ClamService) CleanRecord(req dto.OperateByID) error {
|
||||||
clam, _ := clamRepo.Get(commonRepo.WithByID(req.ID))
|
clam, _ := clamRepo.Get(commonRepo.WithByID(req.ID))
|
||||||
|
|
@ -364,7 +381,6 @@ func loadResultFromLog(pathItem string) dto.ClamLog {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
data.Log = string(file)
|
|
||||||
lines := strings.Split(string(file), "\n")
|
lines := strings.Split(string(file), "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if strings.Contains(line, "- SCAN SUMMARY -") {
|
if strings.Contains(line, "- SCAN SUMMARY -") {
|
||||||
|
|
@ -376,6 +392,8 @@ func loadResultFromLog(pathItem string) dto.ClamLog {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(line, "Infected files:"):
|
case strings.HasPrefix(line, "Infected files:"):
|
||||||
data.InfectedFiles = strings.TrimPrefix(line, "Infected files:")
|
data.InfectedFiles = strings.TrimPrefix(line, "Infected files:")
|
||||||
|
case strings.HasPrefix(line, "Total errors:"):
|
||||||
|
data.TotalError = strings.TrimPrefix(line, "Total errors:")
|
||||||
case strings.HasPrefix(line, "Time:"):
|
case strings.HasPrefix(line, "Time:"):
|
||||||
if strings.Contains(line, "(") {
|
if strings.Contains(line, "(") {
|
||||||
data.ScanTime = strings.ReplaceAll(strings.Split(line, "(")[1], ")", "")
|
data.ScanTime = strings.ReplaceAll(strings.Split(line, "(")[1], ")", "")
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ func (s *ToolboxRouter) InitRouter(Router *gin.RouterGroup) {
|
||||||
toolboxRouter.POST("/clam/search", baseApi.SearchClam)
|
toolboxRouter.POST("/clam/search", baseApi.SearchClam)
|
||||||
toolboxRouter.POST("/clam/record/search", baseApi.SearchClamRecord)
|
toolboxRouter.POST("/clam/record/search", baseApi.SearchClamRecord)
|
||||||
toolboxRouter.POST("/clam/record/clean", baseApi.CleanClamRecord)
|
toolboxRouter.POST("/clam/record/clean", baseApi.CleanClamRecord)
|
||||||
|
toolboxRouter.POST("/clam/record/log", baseApi.LoadClamRecordLog)
|
||||||
toolboxRouter.POST("/clam/file/search", baseApi.SearchClamFile)
|
toolboxRouter.POST("/clam/file/search", baseApi.SearchClamFile)
|
||||||
toolboxRouter.POST("/clam/file/update", baseApi.UpdateFile)
|
toolboxRouter.POST("/clam/file/update", baseApi.UpdateFile)
|
||||||
toolboxRouter.POST("/clam", baseApi.CreateClam)
|
toolboxRouter.POST("/clam", baseApi.CreateClam)
|
||||||
|
|
|
||||||
|
|
@ -11395,6 +11395,39 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/toolbox/clam/record/log": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "获取扫描结果详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Clam"
|
||||||
|
],
|
||||||
|
"summary": "Load clam record detail",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.ClamLogReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/toolbox/clam/record/search": {
|
"/toolbox/clam/record/search": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -15495,11 +15528,25 @@ const docTemplate = `{
|
||||||
"removeInfected": {
|
"removeInfected": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"removeResult": {
|
"removeRecord": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.ClamLogReq": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"clamName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"recordName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tail": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dto.ClamLogSearch": {
|
"dto.ClamLogSearch": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -11388,6 +11388,39 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/toolbox/clam/record/log": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "获取扫描结果详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Clam"
|
||||||
|
],
|
||||||
|
"summary": "Load clam record detail",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.ClamLogReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/toolbox/clam/record/search": {
|
"/toolbox/clam/record/search": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -15488,11 +15521,25 @@
|
||||||
"removeInfected": {
|
"removeInfected": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"removeResult": {
|
"removeRecord": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.ClamLogReq": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"clamName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"recordName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tail": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dto.ClamLogSearch": {
|
"dto.ClamLogSearch": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -246,11 +246,20 @@ definitions:
|
||||||
type: array
|
type: array
|
||||||
removeInfected:
|
removeInfected:
|
||||||
type: boolean
|
type: boolean
|
||||||
removeResult:
|
removeRecord:
|
||||||
type: boolean
|
type: boolean
|
||||||
required:
|
required:
|
||||||
- ids
|
- ids
|
||||||
type: object
|
type: object
|
||||||
|
dto.ClamLogReq:
|
||||||
|
properties:
|
||||||
|
clamName:
|
||||||
|
type: string
|
||||||
|
recordName:
|
||||||
|
type: string
|
||||||
|
tail:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
dto.ClamLogSearch:
|
dto.ClamLogSearch:
|
||||||
properties:
|
properties:
|
||||||
clamID:
|
clamID:
|
||||||
|
|
@ -12669,6 +12678,26 @@ paths:
|
||||||
formatEN: clean clam record [name]
|
formatEN: clean clam record [name]
|
||||||
formatZH: 清空扫描报告 [name]
|
formatZH: 清空扫描报告 [name]
|
||||||
paramKeys: []
|
paramKeys: []
|
||||||
|
/toolbox/clam/record/log:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 获取扫描结果详情
|
||||||
|
parameters:
|
||||||
|
- description: request
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/dto.ClamLogReq'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: Load clam record detail
|
||||||
|
tags:
|
||||||
|
- Clam
|
||||||
/toolbox/clam/record/search:
|
/toolbox/clam/record/search:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
||||||
|
|
@ -151,13 +151,17 @@ export namespace Toolbox {
|
||||||
startTime: Date;
|
startTime: Date;
|
||||||
endTime: Date;
|
endTime: Date;
|
||||||
}
|
}
|
||||||
|
export interface ClamRecordReq {
|
||||||
|
tail: string;
|
||||||
|
clamName: string;
|
||||||
|
recordName: string;
|
||||||
|
}
|
||||||
export interface ClamLog {
|
export interface ClamLog {
|
||||||
name: string;
|
name: string;
|
||||||
scanDate: string;
|
scanDate: string;
|
||||||
scanTime: string;
|
scanTime: string;
|
||||||
scannedFiles: string;
|
totalError: string;
|
||||||
infectedFiles: string;
|
infectedFiles: string;
|
||||||
log: string;
|
|
||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,9 @@ export const cleanClamRecord = (id: number) => {
|
||||||
export const searchClamRecord = (param: Toolbox.ClamSearchLog) => {
|
export const searchClamRecord = (param: Toolbox.ClamSearchLog) => {
|
||||||
return http.post<ResPage<Toolbox.ClamLog>>(`/toolbox/clam/record/search`, param);
|
return http.post<ResPage<Toolbox.ClamLog>>(`/toolbox/clam/record/search`, param);
|
||||||
};
|
};
|
||||||
|
export const getClamRecordLog = (param: Toolbox.ClamRecordReq) => {
|
||||||
|
return http.post<string>(`/toolbox/clam/record/log`, param);
|
||||||
|
};
|
||||||
export const searchClamFile = (name: string) => {
|
export const searchClamFile = (name: string) => {
|
||||||
return http.post<string>(`/toolbox/clam/file/search`, { name: name });
|
return http.post<string>(`/toolbox/clam/file/search`, { name: name });
|
||||||
};
|
};
|
||||||
|
|
@ -135,7 +138,7 @@ export const createClam = (params: Toolbox.ClamCreate) => {
|
||||||
export const updateClam = (params: Toolbox.ClamUpdate) => {
|
export const updateClam = (params: Toolbox.ClamUpdate) => {
|
||||||
return http.post(`/toolbox/clam/update`, params);
|
return http.post(`/toolbox/clam/update`, params);
|
||||||
};
|
};
|
||||||
export const deleteClam = (params: { ids: number[]; removeResult: boolean; removeInfected: boolean }) => {
|
export const deleteClam = (params: { ids: number[]; removeRecord: boolean; removeInfected: boolean }) => {
|
||||||
return http.post(`/toolbox/clam/del`, params);
|
return http.post(`/toolbox/clam/del`, params);
|
||||||
};
|
};
|
||||||
export const handleClamScan = (id: number) => {
|
export const handleClamScan = (id: number) => {
|
||||||
|
|
|
||||||
|
|
@ -1081,7 +1081,7 @@ const message = {
|
||||||
removeInfectedHelper:
|
removeInfectedHelper:
|
||||||
'Delete virus files detected during the task to ensure server security and normal operation.',
|
'Delete virus files detected during the task to ensure server security and normal operation.',
|
||||||
clamCreate: 'Create Scan Rules',
|
clamCreate: 'Create Scan Rules',
|
||||||
infectedStrategy: 'Virus Strategy',
|
infectedStrategy: 'Infected Strategy',
|
||||||
remove: 'Delete',
|
remove: 'Delete',
|
||||||
removeHelper: 'Delete virus files, choose carefully!',
|
removeHelper: 'Delete virus files, choose carefully!',
|
||||||
move: 'Move',
|
move: 'Move',
|
||||||
|
|
@ -1093,8 +1093,8 @@ const message = {
|
||||||
scanDir: 'Scan Directory',
|
scanDir: 'Scan Directory',
|
||||||
infectedDir: 'Infected Directory',
|
infectedDir: 'Infected Directory',
|
||||||
scanDate: 'Scan Date',
|
scanDate: 'Scan Date',
|
||||||
|
scanResult: 'Scan log tail',
|
||||||
scanTime: 'Time Taken',
|
scanTime: 'Time Taken',
|
||||||
scannedFiles: 'Scanned Files',
|
|
||||||
infectedFiles: 'Infected Files',
|
infectedFiles: 'Infected Files',
|
||||||
log: 'Details',
|
log: 'Details',
|
||||||
clamConf: 'Scan Configuration',
|
clamConf: 'Scan Configuration',
|
||||||
|
|
|
||||||
|
|
@ -1022,7 +1022,7 @@ const message = {
|
||||||
removeInfected: '刪除病毒文件',
|
removeInfected: '刪除病毒文件',
|
||||||
removeInfectedHelper: '刪除任務檢測到的病毒文件,以確保伺服器的安全和正常運行。',
|
removeInfectedHelper: '刪除任務檢測到的病毒文件,以確保伺服器的安全和正常運行。',
|
||||||
clamCreate: '創建掃描規則',
|
clamCreate: '創建掃描規則',
|
||||||
infectedStrategy: '病毒策略',
|
infectedStrategy: '感染文件策略',
|
||||||
remove: '刪除',
|
remove: '刪除',
|
||||||
removeHelper: '刪除病毒文件,請謹慎選擇!',
|
removeHelper: '刪除病毒文件,請謹慎選擇!',
|
||||||
move: '移動',
|
move: '移動',
|
||||||
|
|
@ -1032,11 +1032,11 @@ const message = {
|
||||||
none: '不操作',
|
none: '不操作',
|
||||||
noneHelper: '不對病毒文件採取任何操作',
|
noneHelper: '不對病毒文件採取任何操作',
|
||||||
scanDir: '掃描目錄',
|
scanDir: '掃描目錄',
|
||||||
infectedDir: '病毒目錄',
|
infectedDir: '隔離目錄',
|
||||||
scanDate: '掃描時間',
|
scanDate: '掃描時間',
|
||||||
|
scanResult: '掃描報告條數',
|
||||||
scanTime: '耗時',
|
scanTime: '耗時',
|
||||||
scannedFiles: '掃描文件數',
|
infectedFiles: '感染文件數',
|
||||||
infectedFiles: '危險文件數',
|
|
||||||
log: '詳情',
|
log: '詳情',
|
||||||
clamConf: '掃描配置',
|
clamConf: '掃描配置',
|
||||||
clamLog: '掃描日誌',
|
clamLog: '掃描日誌',
|
||||||
|
|
|
||||||
|
|
@ -1023,7 +1023,7 @@ const message = {
|
||||||
removeInfected: '删除病毒文件',
|
removeInfected: '删除病毒文件',
|
||||||
removeInfectedHelper: '删除任务检测到的病毒文件,以确保服务器的安全和正常运行。',
|
removeInfectedHelper: '删除任务检测到的病毒文件,以确保服务器的安全和正常运行。',
|
||||||
clamCreate: '创建扫描规则',
|
clamCreate: '创建扫描规则',
|
||||||
infectedStrategy: '病毒策略',
|
infectedStrategy: '感染文件策略',
|
||||||
remove: '删除',
|
remove: '删除',
|
||||||
removeHelper: '删除病毒文件,请谨慎选择!',
|
removeHelper: '删除病毒文件,请谨慎选择!',
|
||||||
move: '移动',
|
move: '移动',
|
||||||
|
|
@ -1033,11 +1033,11 @@ const message = {
|
||||||
none: '不操作',
|
none: '不操作',
|
||||||
noneHelper: '不对病毒文件采取任何操作',
|
noneHelper: '不对病毒文件采取任何操作',
|
||||||
scanDir: '扫描目录',
|
scanDir: '扫描目录',
|
||||||
infectedDir: '病毒目录',
|
infectedDir: '隔离目录',
|
||||||
scanDate: '扫描时间',
|
scanDate: '扫描时间',
|
||||||
|
scanResult: '扫描报告条数',
|
||||||
scanTime: '耗时',
|
scanTime: '耗时',
|
||||||
scannedFiles: '扫描文件数',
|
infectedFiles: '感染文件数',
|
||||||
infectedFiles: '危险文件数',
|
|
||||||
log: '详情',
|
log: '详情',
|
||||||
clamConf: '扫描配置',
|
clamConf: '扫描配置',
|
||||||
clamLog: '扫描日志',
|
clamLog: '扫描日志',
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
|
import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
|
||||||
import { Cronjob } from '@/api/interface/cronjob';
|
import { Cronjob } from '@/api/interface/cronjob';
|
||||||
import { searchRecords, handleOnce, updateStatus, cleanRecords, getRecordLog } from '@/api/modules/cronjob';
|
import { searchRecords, handleOnce, updateStatus, cleanRecords, getRecordLog } from '@/api/modules/cronjob';
|
||||||
import { dateFormat } from '@/utils/util';
|
import { dateFormat } from '@/utils/util';
|
||||||
|
|
@ -415,10 +415,12 @@ const loadRecord = async (row: Cronjob.Record) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentRecordDetail.value = log;
|
currentRecordDetail.value = log;
|
||||||
const state = view.value.state;
|
nextTick(() => {
|
||||||
view.value.dispatch({
|
const state = view.value.state;
|
||||||
selection: { anchor: state.doc.length, head: state.doc.length },
|
view.value.dispatch({
|
||||||
scrollIntoView: true,
|
selection: { anchor: state.doc.length, head: state.doc.length },
|
||||||
|
scrollIntoView: true,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,13 @@
|
||||||
:min-width="60"
|
:min-width="60"
|
||||||
prop="name"
|
prop="name"
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
/>
|
>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-text type="primary" class="cursor-pointer" @click="onOpenRecord(row)">
|
||||||
|
{{ row.name }}
|
||||||
|
</el-text>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
:label="$t('toolbox.clam.scanDir')"
|
:label="$t('toolbox.clam.scanDir')"
|
||||||
:min-width="120"
|
:min-width="120"
|
||||||
|
|
@ -115,7 +121,7 @@
|
||||||
<template #content>
|
<template #content>
|
||||||
<el-form class="mt-4 mb-1" ref="deleteForm" label-position="left">
|
<el-form class="mt-4 mb-1" ref="deleteForm" label-position="left">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-checkbox v-model="removeResult" :label="$t('toolbox.clam.removeResult')" />
|
<el-checkbox v-model="removeRecord" :label="$t('toolbox.clam.removeRecord')" />
|
||||||
<span class="input-help">{{ $t('toolbox.clam.removeResultHelper') }}</span>
|
<span class="input-help">{{ $t('toolbox.clam.removeResultHelper') }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
|
|
@ -163,7 +169,7 @@ const operateIDs = ref();
|
||||||
const dialogLogRef = ref();
|
const dialogLogRef = ref();
|
||||||
const isRecordShow = ref();
|
const isRecordShow = ref();
|
||||||
|
|
||||||
const removeResult = ref();
|
const removeRecord = ref();
|
||||||
const removeInfected = ref();
|
const removeInfected = ref();
|
||||||
|
|
||||||
const isSettingShow = ref();
|
const isSettingShow = ref();
|
||||||
|
|
@ -223,6 +229,13 @@ const onOpenDialog = async (
|
||||||
};
|
};
|
||||||
dialogRef.value!.acceptParams(params);
|
dialogRef.value!.acceptParams(params);
|
||||||
};
|
};
|
||||||
|
const onOpenRecord = (row: Toolbox.ClamInfo) => {
|
||||||
|
isRecordShow.value = true;
|
||||||
|
let params = {
|
||||||
|
rowData: { ...row },
|
||||||
|
};
|
||||||
|
dialogLogRef.value!.acceptParams(params);
|
||||||
|
};
|
||||||
|
|
||||||
const onDelete = async (row: Toolbox.ClamInfo | null) => {
|
const onDelete = async (row: Toolbox.ClamInfo | null) => {
|
||||||
let names = [];
|
let names = [];
|
||||||
|
|
@ -251,7 +264,7 @@ const onDelete = async (row: Toolbox.ClamInfo | null) => {
|
||||||
|
|
||||||
const onSubmitDelete = async () => {
|
const onSubmitDelete = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await deleteClam({ ids: operateIDs.value, removeResult: removeResult.value, removeInfected: removeInfected.value })
|
await deleteClam({ ids: operateIDs.value, removeRecord: removeRecord.value, removeInfected: removeInfected.value })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
MsgSuccess(i18n.global.t('commons.msg.deleteSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.deleteSuccess'));
|
||||||
|
|
@ -287,11 +300,7 @@ const buttons = [
|
||||||
{
|
{
|
||||||
label: i18n.global.t('cronjob.record'),
|
label: i18n.global.t('cronjob.record'),
|
||||||
click: (row: Toolbox.ClamInfo) => {
|
click: (row: Toolbox.ClamInfo) => {
|
||||||
isRecordShow.value = true;
|
onOpenRecord(row);
|
||||||
let params = {
|
|
||||||
rowData: { ...row },
|
|
||||||
};
|
|
||||||
dialogLogRef.value!.acceptParams(params);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
effect="dark"
|
effect="dark"
|
||||||
type="success"
|
type="success"
|
||||||
>
|
>
|
||||||
{{ $t('file.path') }}: {{ dialogData.rowData.path }}
|
{{ $t('toolbox.clam.scanDir') }}: {{ dialogData.rowData.path }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
|
|
||||||
<span class="buttons">
|
<span class="buttons">
|
||||||
|
|
@ -125,22 +125,34 @@
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row v-if="currentRecord?.log">
|
<el-row>
|
||||||
<span>{{ $t('commons.table.records') }}</span>
|
<el-select
|
||||||
|
class="descriptionWide"
|
||||||
|
@change="search"
|
||||||
|
v-model.number="searchInfo.tail"
|
||||||
|
>
|
||||||
|
<template #prefix>{{ $t('toolbox.clam.scanResult') }}</template>
|
||||||
|
<el-option :value="0" :label="$t('commons.table.all')" />
|
||||||
|
<el-option :value="10" :label="10" />
|
||||||
|
<el-option :value="100" :label="100" />
|
||||||
|
<el-option :value="200" :label="200" />
|
||||||
|
<el-option :value="500" :label="500" />
|
||||||
|
<el-option :value="1000" :label="1000" />
|
||||||
|
</el-select>
|
||||||
<codemirror
|
<codemirror
|
||||||
ref="mymirror"
|
ref="mymirror"
|
||||||
:autofocus="true"
|
:autofocus="true"
|
||||||
:placeholder="$t('cronjob.noLogs')"
|
:placeholder="$t('cronjob.noLogs')"
|
||||||
:indent-with-tab="true"
|
:indent-with-tab="true"
|
||||||
:tabSize="4"
|
:tabSize="4"
|
||||||
style="height: calc(100vh - 488px); width: 100%; margin-top: 5px"
|
style="height: calc(100vh - 498px); width: 100%; margin-top: 5px"
|
||||||
:lineWrapping="true"
|
:lineWrapping="true"
|
||||||
:matchBrackets="true"
|
:matchBrackets="true"
|
||||||
theme="cobalt"
|
theme="cobalt"
|
||||||
:styleActiveLine="true"
|
:styleActiveLine="true"
|
||||||
:extensions="extensions"
|
:extensions="extensions"
|
||||||
@ready="handleReady"
|
@ready="handleReady"
|
||||||
v-model="currentRecord.log"
|
v-model="logContent"
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
/>
|
/>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
@ -162,7 +174,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
|
import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElMessageBox } from 'element-plus';
|
import { ElMessageBox } from 'element-plus';
|
||||||
import { Codemirror } from 'vue-codemirror';
|
import { Codemirror } from 'vue-codemirror';
|
||||||
|
|
@ -171,7 +183,7 @@ import { oneDark } from '@codemirror/theme-one-dark';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
import { shortcuts } from '@/utils/shortcuts';
|
import { shortcuts } from '@/utils/shortcuts';
|
||||||
import { Toolbox } from '@/api/interface/toolbox';
|
import { Toolbox } from '@/api/interface/toolbox';
|
||||||
import { cleanClamRecord, handleClamScan, searchClamRecord } from '@/api/modules/toolbox';
|
import { cleanClamRecord, getClamRecordLog, handleClamScan, searchClamRecord } from '@/api/modules/toolbox';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
@ -195,6 +207,7 @@ interface DialogProps {
|
||||||
const dialogData = ref();
|
const dialogData = ref();
|
||||||
const records = ref<Array<Toolbox.ClamLog>>([]);
|
const records = ref<Array<Toolbox.ClamLog>>([]);
|
||||||
const currentRecord = ref<Toolbox.ClamLog>();
|
const currentRecord = ref<Toolbox.ClamLog>();
|
||||||
|
const logContent = ref();
|
||||||
|
|
||||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||||
let itemSize = Number(localStorage.getItem(searchInfo.cacheSizeKey));
|
let itemSize = Number(localStorage.getItem(searchInfo.cacheSizeKey));
|
||||||
|
|
@ -233,8 +246,8 @@ const searchInfo = reactive({
|
||||||
cacheSizeKey: 'clam-record-page-size',
|
cacheSizeKey: 'clam-record-page-size',
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 8,
|
pageSize: 8,
|
||||||
|
tail: '100',
|
||||||
recordTotal: 0,
|
recordTotal: 0,
|
||||||
cronjobID: 0,
|
|
||||||
startTime: new Date(),
|
startTime: new Date(),
|
||||||
endTime: new Date(),
|
endTime: new Date(),
|
||||||
});
|
});
|
||||||
|
|
@ -268,6 +281,7 @@ const search = async () => {
|
||||||
page: searchInfo.page,
|
page: searchInfo.page,
|
||||||
pageSize: searchInfo.pageSize,
|
pageSize: searchInfo.pageSize,
|
||||||
clamID: dialogData.value.rowData!.id,
|
clamID: dialogData.value.rowData!.id,
|
||||||
|
tail: searchInfo.tail,
|
||||||
startTime: searchInfo.startTime,
|
startTime: searchInfo.startTime,
|
||||||
endTime: searchInfo.endTime,
|
endTime: searchInfo.endTime,
|
||||||
};
|
};
|
||||||
|
|
@ -281,10 +295,32 @@ const search = async () => {
|
||||||
if (!currentRecord.value) {
|
if (!currentRecord.value) {
|
||||||
currentRecord.value = records.value[0];
|
currentRecord.value = records.value[0];
|
||||||
}
|
}
|
||||||
|
loadRecordLog();
|
||||||
};
|
};
|
||||||
|
|
||||||
const clickRow = async (row: Toolbox.ClamLog) => {
|
const clickRow = async (row: Toolbox.ClamLog) => {
|
||||||
currentRecord.value = row;
|
currentRecord.value = row;
|
||||||
|
loadRecordLog();
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadRecordLog = async () => {
|
||||||
|
let param = {
|
||||||
|
tail: searchInfo.tail + '',
|
||||||
|
clamName: dialogData.value.rowData?.name,
|
||||||
|
recordName: currentRecord.value.name,
|
||||||
|
};
|
||||||
|
const res = await getClamRecordLog(param);
|
||||||
|
if (logContent.value === res.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logContent.value = res.data;
|
||||||
|
nextTick(() => {
|
||||||
|
const state = view.value.state;
|
||||||
|
view.value.dispatch({
|
||||||
|
selection: { anchor: state.doc.length, head: state.doc.length },
|
||||||
|
scrollIntoView: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClean = async () => {
|
const onClean = async () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue