Devosend
3 years ago
committed by
GitHub
7 changed files with 533 additions and 8 deletions
@ -0,0 +1,376 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
import _ from 'lodash' |
||||
import { |
||||
defineComponent, |
||||
PropType, |
||||
Transition, |
||||
toRefs, |
||||
ref, |
||||
onMounted, |
||||
computed, |
||||
reactive, |
||||
renderSlot |
||||
} from 'vue' |
||||
import { useI18n } from 'vue-i18n' |
||||
import { NButton, NIcon, NTooltip } from 'naive-ui' |
||||
import { queryLog } from '@/service/modules/log' |
||||
import { |
||||
DownloadOutlined, |
||||
SyncOutlined, |
||||
FullscreenOutlined, |
||||
FullscreenExitOutlined |
||||
} from '@vicons/antd' |
||||
import { downloadFile } from '@/service/service' |
||||
import styles from './log.module.scss' |
||||
|
||||
const props = { |
||||
taskInstanceId: { |
||||
type: Number as PropType<number>, |
||||
default: -1 |
||||
}, |
||||
taskInstanceType: { |
||||
type: String as PropType<string>, |
||||
default: '' |
||||
} |
||||
} |
||||
|
||||
export default defineComponent({ |
||||
name: 'workflow-instance-log', |
||||
props, |
||||
emits: ['hideLog'], |
||||
setup(props, ctx) { |
||||
const { t } = useI18n() |
||||
|
||||
const loadingRef = ref(false) |
||||
const loadingIndex = ref(0) |
||||
const isDataRef = ref(true) |
||||
const logBox = ref() |
||||
const logContent = ref() |
||||
const logContentBox = ref() |
||||
const textareaLog = ref() |
||||
const isScreen = ref(false) |
||||
const textareaHeight = computed(() => |
||||
logContentBox.value ? logContentBox.value.clientHeight : 0 |
||||
) |
||||
|
||||
const boxRef = reactive({ |
||||
width: '', |
||||
height: '', |
||||
marginLeft: '', |
||||
marginRight: '', |
||||
marginTop: '' |
||||
}) |
||||
|
||||
const refreshLog = () => { |
||||
loadingRef.value = true |
||||
queryLog({ |
||||
taskInstanceId: props.taskInstanceId, |
||||
skipLineNum: loadingIndex.value * 1000, |
||||
limit: loadingIndex.value === 0 ? 1000 : (loadingIndex.value + 1) * 1000 |
||||
}) |
||||
.then((res: any) => { |
||||
setTimeout(() => { |
||||
loadingRef.value = false |
||||
if (res) { |
||||
window.$message.success(t('project.workflow.update_log_success')) |
||||
} else { |
||||
window.$message.warning(t('project.workflow.no_more_log')) |
||||
} |
||||
}, 1500) |
||||
textareaLog.value.innerHTML = res || t('project.workflow.no_log') |
||||
}) |
||||
.catch((error: any) => { |
||||
window.$message.error(error.message || '') |
||||
loadingRef.value = false |
||||
}) |
||||
} |
||||
|
||||
const showLog = () => { |
||||
queryLog({ |
||||
taskInstanceId: props.taskInstanceId, |
||||
skipLineNum: loadingIndex.value * 1000, |
||||
limit: loadingIndex.value === 0 ? 1000 : (loadingIndex.value + 1) * 1000 |
||||
}) |
||||
.then((res: any) => { |
||||
if (!res) { |
||||
isDataRef.value = false |
||||
setTimeout(() => { |
||||
window.$message.warning(t('project.workflow.no_more_log')) |
||||
}, 1000) |
||||
textareaLog.value.innerHTML = t('project.workflow.no_log') |
||||
} else { |
||||
isDataRef.value = true |
||||
textareaLog.value.innerHTML = res || t('project.workflow.no_log') |
||||
setTimeout(() => { |
||||
textareaLog.value.scrollTop = 2 |
||||
}, 800) |
||||
} |
||||
}) |
||||
.catch((error: any) => { |
||||
window.$message.error(error.message || '') |
||||
}) |
||||
} |
||||
|
||||
const initLog = () => { |
||||
window.$message.info(t('project.workflow.loading_log')) |
||||
showLog() |
||||
} |
||||
|
||||
const downloadLog = () => { |
||||
downloadFile('log/download-log', { |
||||
taskInstanceId: props.taskInstanceId |
||||
}) |
||||
} |
||||
|
||||
const screenOpen = () => { |
||||
isScreen.value = true |
||||
const winW = window.innerWidth - 40 |
||||
const winH = window.innerHeight - 40 |
||||
|
||||
boxRef.width = `${winW}px` |
||||
boxRef.height = `${winH}px` |
||||
boxRef.marginLeft = `-${winW / 2}px` |
||||
boxRef.marginRight = `-${winH / 2}px` |
||||
boxRef.marginTop = `-${winH / 2}px` |
||||
|
||||
logContent.value.animate({ scrollTop: 0 }, 0) |
||||
} |
||||
|
||||
const screenClose = () => { |
||||
isScreen.value = false |
||||
boxRef.width = '' |
||||
boxRef.height = '' |
||||
boxRef.marginLeft = '' |
||||
boxRef.marginRight = '' |
||||
boxRef.marginTop = '' |
||||
|
||||
logContent.value.animate({ scrollTop: 0 }, 0) |
||||
} |
||||
|
||||
const toggleScreen = () => { |
||||
if (isScreen.value) { |
||||
screenClose() |
||||
} else { |
||||
screenOpen() |
||||
} |
||||
} |
||||
|
||||
const close = () => { |
||||
ctx.emit('hideLog') |
||||
} |
||||
|
||||
/** |
||||
* up |
||||
*/ |
||||
const onUp = _.debounce( |
||||
function () { |
||||
loadingIndex.value = loadingIndex.value - 1 |
||||
showLog() |
||||
}, |
||||
1000, |
||||
{ |
||||
leading: false, |
||||
trailing: true |
||||
} |
||||
) |
||||
|
||||
/** |
||||
* down |
||||
*/ |
||||
const onDown = _.debounce( |
||||
function () { |
||||
loadingIndex.value = loadingIndex.value + 1 |
||||
showLog() |
||||
}, |
||||
1000, |
||||
{ |
||||
leading: false, |
||||
trailing: true |
||||
} |
||||
) |
||||
|
||||
const onTextareaScroll = () => { |
||||
textareaLog.value.onscroll = () => { |
||||
// Listen for scrollbar events
|
||||
if ( |
||||
textareaLog.value.scrollTop + textareaLog.value.clientHeight === |
||||
textareaLog.value.clientHeight |
||||
) { |
||||
if (loadingIndex.value > 0) { |
||||
window.$message.info(t('project.workflow.loading_log')) |
||||
onUp() |
||||
} |
||||
} |
||||
// Listen for scrollbar events
|
||||
if ( |
||||
textareaLog.value.scrollHeight === |
||||
textareaLog.value.clientHeight + textareaLog.value.scrollTop |
||||
) { |
||||
// No data is not requested
|
||||
if (isDataRef.value) { |
||||
window.$message.info(t('project.workflow.loading_log')) |
||||
onDown() |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
onMounted(() => { |
||||
initLog() |
||||
onTextareaScroll() |
||||
}) |
||||
|
||||
return { |
||||
t, |
||||
logBox, |
||||
logContentBox, |
||||
loadingRef, |
||||
textareaLog, |
||||
logContent, |
||||
textareaHeight, |
||||
isScreen, |
||||
boxRef, |
||||
showLog, |
||||
downloadLog, |
||||
refreshLog, |
||||
toggleScreen, |
||||
close, |
||||
...toRefs(props) |
||||
} |
||||
}, |
||||
render() { |
||||
return ( |
||||
<div> |
||||
<span class={styles['log-model']}> |
||||
{this.taskInstanceId && this.taskInstanceType !== 'SUB_PROCESS' && ( |
||||
<span> |
||||
{renderSlot(this.$slots, 'history')} |
||||
<slot name='history'></slot> |
||||
<span onClick={this.showLog}> |
||||
{renderSlot(this.$slots, 'log')} |
||||
</span> |
||||
</span> |
||||
)} |
||||
<Transition name='fade'> |
||||
{ |
||||
<div class={styles['log-pop']}> |
||||
<div class={styles['log-box']} style={{ ...this.boxRef }}> |
||||
<div class={styles['title']}> |
||||
<div class={styles['left-item']}> |
||||
{this.t('project.workflow.view_log')} |
||||
</div> |
||||
<div class={styles['right-item']}> |
||||
<NTooltip> |
||||
{{ |
||||
trigger: () => ( |
||||
<NButton |
||||
strong |
||||
secondary |
||||
circle |
||||
type='info' |
||||
class={styles.button} |
||||
onClick={this.downloadLog} |
||||
> |
||||
<NIcon> |
||||
<DownloadOutlined /> |
||||
</NIcon> |
||||
</NButton> |
||||
), |
||||
default: () => this.t('project.workflow.download_log') |
||||
}} |
||||
</NTooltip> |
||||
<NTooltip> |
||||
{{ |
||||
trigger: () => ( |
||||
<NButton |
||||
strong |
||||
secondary |
||||
circle |
||||
type='info' |
||||
class={styles.button} |
||||
onClick={() => |
||||
!this.loadingRef && this.refreshLog() |
||||
} |
||||
> |
||||
<NIcon> |
||||
<SyncOutlined /> |
||||
</NIcon> |
||||
</NButton> |
||||
), |
||||
default: () => this.t('project.workflow.refresh_log') |
||||
}} |
||||
</NTooltip> |
||||
<NTooltip> |
||||
{{ |
||||
trigger: () => ( |
||||
<NButton |
||||
strong |
||||
secondary |
||||
circle |
||||
type='info' |
||||
class={styles.button} |
||||
onClick={this.toggleScreen} |
||||
> |
||||
<NIcon> |
||||
{this.isScreen ? ( |
||||
<FullscreenExitOutlined /> |
||||
) : ( |
||||
<FullscreenOutlined /> |
||||
)} |
||||
</NIcon> |
||||
</NButton> |
||||
), |
||||
default: () => |
||||
this.isScreen |
||||
? this.t('project.workflow.cancel_full_screen') |
||||
: this.t('project.workflow.enter_full_screen') |
||||
}} |
||||
</NTooltip> |
||||
</div> |
||||
</div> |
||||
<div class={styles['content']} ref='logContent'> |
||||
<div class={styles['content-log-box']} ref='logContentBox'> |
||||
<textarea |
||||
class={styles['textarea-ft']} |
||||
style={`width: 100%; height: ${this.textareaHeight}px`} |
||||
spellcheck='false' |
||||
ref='textareaLog' |
||||
readonly |
||||
></textarea> |
||||
</div> |
||||
</div> |
||||
<div class={styles['operation']}> |
||||
<NButton |
||||
type='primary' |
||||
size='small' |
||||
round |
||||
onClick={this.close} |
||||
> |
||||
{this.t('project.workflow.close')} |
||||
</NButton> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
} |
||||
</Transition> |
||||
</span> |
||||
</div> |
||||
) |
||||
} |
||||
}) |
@ -0,0 +1,97 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
.log-pop { |
||||
position: fixed; |
||||
left: 0; |
||||
top: 0; |
||||
width: 100%; |
||||
height: 100%; |
||||
background: rgba(0,0,0,.4); |
||||
z-index: 10; |
||||
.log-box { |
||||
width: 660px; |
||||
height: 520px; |
||||
background: #fff; |
||||
border-radius: 3px; |
||||
position: absolute; |
||||
left:50%; |
||||
top: 50%; |
||||
margin-left: -340px; |
||||
margin-top: -250px; |
||||
.title { |
||||
height: 50px; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
border-bottom: 1px solid #dcdedc; |
||||
.left-item { |
||||
font-size: 16px; |
||||
color: #333; |
||||
display: inline-block; |
||||
padding-left: 20px; |
||||
} |
||||
.right-item { |
||||
padding-right: 10px; |
||||
.button { |
||||
margin-right: 10px; |
||||
} |
||||
} |
||||
} |
||||
.content { |
||||
height: calc(100% - 100px); |
||||
background: #002A35; |
||||
padding:6px 2px; |
||||
.content-log-box { |
||||
width: 100%; |
||||
height: 100%; |
||||
word-break:break-all; |
||||
textarea { |
||||
background: none; |
||||
color: #9CABAF; |
||||
border: 0; |
||||
font-family: 'Microsoft Yahei,Arial,Hiragino Sans GB,tahoma,SimSun,sans-serif'; |
||||
font-weight: bold; |
||||
resize:none; |
||||
line-height: 1.6; |
||||
padding: 0px; |
||||
} |
||||
} |
||||
} |
||||
.operation { |
||||
text-align: right; |
||||
height: 50px; |
||||
line-height: 44px; |
||||
border-top: 1px solid #dcdedc; |
||||
padding-right: 20px; |
||||
background: #fff; |
||||
position: relative; |
||||
} |
||||
} |
||||
} |
||||
@-webkit-keyframes rotateloading{from{-webkit-transform: rotate(0deg)} |
||||
to{-webkit-transform: rotate(360deg)} |
||||
} |
||||
@-moz-keyframes rotateloading{from{-moz-transform: rotate(0deg)} |
||||
to{-moz-transform: rotate(359deg)} |
||||
} |
||||
@-o-keyframes rotateloading{from{-o-transform: rotate(0deg)} |
||||
to{-o-transform: rotate(359deg)} |
||||
} |
||||
@keyframes rotateloading{from{transform: rotate(0deg)} |
||||
to{transform: rotate(359deg)} |
||||
} |
Loading…
Reference in new issue