198 lines
6.1 KiB
Vue
198 lines
6.1 KiB
Vue
<script setup>
|
|
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
|
import { debounce, filter, get, includes, isEmpty, join } from 'lodash'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { useThemeVars } from 'naive-ui'
|
|
import Play from '@/components/icons/Play.vue'
|
|
import Pause from '@/components/icons/Pause.vue'
|
|
import { ExportLog, StartMonitor, StopMonitor } from 'wailsjs/go/services/monitorService.js'
|
|
import { EventsOff, EventsOn } from 'wailsjs/runtime/runtime.js'
|
|
import Copy from '@/components/icons/Copy.vue'
|
|
import Export from '@/components/icons/Export.vue'
|
|
import Delete from '@/components/icons/Delete.vue'
|
|
import IconButton from '@/components/common/IconButton.vue'
|
|
import Bottom from '@/components/icons/Bottom.vue'
|
|
import copy from 'copy-text-to-clipboard'
|
|
|
|
const themeVars = useThemeVars()
|
|
|
|
const i18n = useI18n()
|
|
const props = defineProps({
|
|
server: {
|
|
type: String,
|
|
},
|
|
})
|
|
|
|
const data = reactive({
|
|
monitorEvent: '',
|
|
list: [],
|
|
listLimit: 20,
|
|
keyword: '',
|
|
autoShowLast: true,
|
|
})
|
|
|
|
const listRef = ref(null)
|
|
|
|
onMounted(() => {
|
|
// try to stop prev monitor first
|
|
onStopMonitor()
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
onStopMonitor()
|
|
})
|
|
|
|
const isMonitoring = computed(() => {
|
|
return !isEmpty(data.monitorEvent)
|
|
})
|
|
|
|
const displayList = computed(() => {
|
|
if (!isEmpty(data.keyword)) {
|
|
return filter(data.list, (line) => includes(line, data.keyword))
|
|
}
|
|
return data.list
|
|
})
|
|
|
|
const _scrollToBottom = () => {
|
|
nextTick(() => {
|
|
listRef.value?.scrollTo({ position: 'bottom' })
|
|
})
|
|
}
|
|
const scrollToBottom = debounce(_scrollToBottom, 1000, { leading: true, trailing: true })
|
|
|
|
const onStartMonitor = async () => {
|
|
if (isMonitoring.value) {
|
|
return
|
|
}
|
|
|
|
const { data: ret, success, msg } = await StartMonitor(props.server)
|
|
if (!success) {
|
|
$message.error(msg)
|
|
return
|
|
}
|
|
data.monitorEvent = get(ret, 'eventName')
|
|
EventsOn(data.monitorEvent, (content) => {
|
|
if (content instanceof Array) {
|
|
data.list.push(...content)
|
|
} else {
|
|
data.list.push(content)
|
|
}
|
|
if (data.autoShowLast) {
|
|
scrollToBottom()
|
|
}
|
|
})
|
|
}
|
|
const onStopMonitor = async () => {
|
|
const { success, msg } = await StopMonitor(props.server)
|
|
if (!success) {
|
|
$message.error(msg)
|
|
return
|
|
}
|
|
|
|
EventsOff(data.monitorEvent)
|
|
data.monitorEvent = ''
|
|
}
|
|
|
|
const onCopyLog = async () => {
|
|
copy(join(data.list, '\n'))
|
|
$message.success(i18n.t('interface.copy_succ'))
|
|
}
|
|
|
|
const onExportLog = () => {
|
|
ExportLog(data.list)
|
|
}
|
|
|
|
const onCleanLog = () => {
|
|
data.list = []
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="content-log content-container fill-height flex-box-v">
|
|
<n-form class="flex-item" label-align="left" label-placement="left" label-width="auto" size="small">
|
|
<n-form-item :feedback="$t('monitor.warning')" :label="$t('monitor.actions')">
|
|
<n-space :wrap="false" :wrap-item="false" style="width: 100%">
|
|
<n-button
|
|
v-if="!isMonitoring"
|
|
:focusable="false"
|
|
secondary
|
|
strong
|
|
type="success"
|
|
@click="onStartMonitor">
|
|
<template #icon>
|
|
<n-icon :component="Play" size="18" />
|
|
</template>
|
|
{{ $t('monitor.start') }}
|
|
</n-button>
|
|
<n-button v-else :focusable="false" secondary strong type="warning" @click="onStopMonitor">
|
|
<template #icon>
|
|
<n-icon :component="Pause" size="18" />
|
|
</template>
|
|
{{ $t('monitor.stop') }}
|
|
</n-button>
|
|
<n-button-group>
|
|
<icon-button
|
|
:icon="Copy"
|
|
border
|
|
size="18"
|
|
stroke-width="3.5"
|
|
t-tooltip="monitor.copy_log"
|
|
@click="onCopyLog" />
|
|
<icon-button
|
|
:icon="Export"
|
|
border
|
|
size="18"
|
|
stroke-width="3.5"
|
|
t-tooltip="monitor.save_log"
|
|
@click="onExportLog" />
|
|
</n-button-group>
|
|
<icon-button
|
|
:icon="Bottom"
|
|
:secondary="data.autoShowLast"
|
|
:type="data.autoShowLast ? 'primary' : 'default'"
|
|
border
|
|
size="18"
|
|
stroke-width="3.5"
|
|
t-tooltip="monitor.always_show_last"
|
|
@click="data.autoShowLast = !data.autoShowLast" />
|
|
<div class="flex-item-expand" />
|
|
<icon-button
|
|
:icon="Delete"
|
|
border
|
|
size="18"
|
|
stroke-width="3.5"
|
|
t-tooltip="monitor.clean_log"
|
|
@click="onCleanLog" />
|
|
</n-space>
|
|
</n-form-item>
|
|
<n-form-item :label="$t('monitor.search')">
|
|
<n-input v-model:value="data.keyword" clearable placeholder="" />
|
|
</n-form-item>
|
|
</n-form>
|
|
<n-virtual-list ref="listRef" :item-size="25" :items="displayList" class="list-wrapper">
|
|
<template #default="{ item }">
|
|
<div class="line-item content-value">
|
|
<b>></b>
|
|
{{ item }}
|
|
</div>
|
|
</template>
|
|
</n-virtual-list>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
@import '@/styles/content';
|
|
|
|
.line-item {
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.list-wrapper {
|
|
background-color: v-bind('themeVars.codeColor');
|
|
border: solid 1px v-bind('themeVars.borderColor');
|
|
border-radius: 3px;
|
|
padding: 5px 10px;
|
|
box-sizing: border-box;
|
|
}
|
|
</style>
|