gtsoft-snail-job-server/frontend/src/views/job/JobBatchLog.vue
2024-04-07 21:34:39 +08:00

258 lines
5.1 KiB
Vue

<template>
<a-modal
:visible="visible"
width="100%"
wrap-class-name="full-modal"
:footer="null"
title="日志详情"
@cancel="onCancel">
<log :value="value" />
</a-modal>
</template>
<script>
import request from '@/utils/request'
import Log from '@/components/Log/index.vue'
export default {
name: 'JobBatchLog',
components: { Log },
props: {
open: {
type: Boolean,
default: false
},
record: {
type: Object,
default: () => {}
},
value: {
type: Array,
default: () => []
}
},
watch: {
value: {
deep: true,
immediate: true,
handler (val) {
this.logList = val
}
},
open: {
deep: true,
immediate: true,
handler (val) {
this.visible = val
}
}
},
data () {
return {
visible: false,
finished: false,
logList: [],
interval: null,
startId: 0,
fromIndex: 0,
controller: new AbortController()
}
},
mounted () {
this.getLogList()
},
beforeDestroy () {
this.stopLog()
},
methods: {
onCancel () {
this.stopLog()
this.$emit('update:open', false)
},
stopLog () {
this.finished = true
this.controller.abort()
clearTimeout(this.interval)
this.interval = undefined
},
getLogList () {
request(
{
url: '/job/log/list',
method: 'get',
params: {
taskBatchId: this.record.taskBatchId,
jobId: this.record.jobId,
taskId: this.record.id,
startId: this.startId,
fromIndex: this.fromIndex,
size: 50
},
signal: this.controller.signal
}
)
.then((res) => {
this.finished = res.data.finished
this.startId = res.data.nextStartId
this.fromIndex = res.data.fromIndex
if (res.data.message) {
this.logList.push(...res.data.message)
this.logList.sort((a, b) => a.time_stamp - b.time_stamp)
}
if (!this.finished) {
clearTimeout(this.interval)
this.interval = setTimeout(this.getLogList, 1000)
}
})
.catch(() => {
this.finished = true
})
}
}
}
</script>
<style scoped lang="less">
.log {
height: calc(100vh - 56px);
color: #abb2bf;
background-color: #282c34;
position: relative !important;
box-sizing: border-box;
display: flex !important;
flex-direction: column;
// 美化滚动条
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
width: 6px;
background: rgba(#101F1C, 0.1);
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius: 2em;
}
::-webkit-scrollbar-thumb {
background-color: rgba(144,147,153,.5);
background-clip: padding-box;
min-height: 28px;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius: 2em;
transition: background-color .3s;
cursor: pointer;
}
::-webkit-scrollbar-thumb:hover {
background-color: rgba(144,147,153,.3);
}
.scroller {
height: 100%;
overflow: auto;
display: flex !important;
align-items: flex-start !important;
font-family: monospace;
line-height: 1.4;
position: relative;
z-index: 0;
.index{
width: 32px;
min-width: 32px;
height: 100%;
background-color: #1e1f22;
color: #7d8799;
text-align: center;
vertical-align: top;
padding-top: 4px;
font-size: 16px;
z-index: 200;
}
.gutters {
min-height: 100%;
position: sticky;
background-color: #1e1f22;
color: #7d8799;
border: none;
flex-shrink: 0;
display: flex;
flex-direction: column;
box-sizing: border-box;
inset-inline-start: 0;
z-index: 200;
.gutter-element {
height: 25px;
font-size: 14px;
padding: 0 8px 0 5px;
min-width: 20px;
text-align: right;
white-space: nowrap;
box-sizing: border-box;
color: #7d8799;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
.content {
tab-size: 4;
caret-color: transparent !important;
margin: 0;
//flex-grow: 2;
//flex-shrink: 0;
// display: block;
white-space: pre;
//word-wrap: normal;
//box-sizing: border-box;
//min-height: 100%;
padding: 4px 8px;
outline: none;
color: #bcbec4;
.line {
height: 25px;
caret-color: transparent !important;
font-size: 16px;
// background-color: #6699ff0b;
display: contents;
padding: 0 2px 0 6px;
.flex{
display: flex;
align-items: center;
gap: 5px;
}
.text {
font-size: 16px;
}
}
}
}
}
/deep/ .ant-modal {
max-width: 100%;
top: 0;
padding-bottom: 0;
margin: 0;
}
/deep/ .ant-modal-content {
display: flex;
flex-direction: column;
height: calc(100vh);
}
/deep/ .ant-modal-body {
flex: 1;
padding: 0;
}
</style>