fix: 优化病毒扫描报告界面 (#5675)

pull/5678/head
ssongliu 5 months ago committed by GitHub
parent a4accc071d
commit f370f7eacf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -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,11 +415,13 @@ const loadRecord = async (row: Cronjob.Record) => {
return; return;
} }
currentRecordDetail.value = log; currentRecordDetail.value = log;
nextTick(() => {
const state = view.value.state; const state = view.value.state;
view.value.dispatch({ view.value.dispatch({
selection: { anchor: state.doc.length, head: state.doc.length }, selection: { anchor: state.doc.length, head: state.doc.length },
scrollIntoView: true, 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…
Cancel
Save