tiny-rdm/frontend/src/components/content/ContentLogPane.vue

163 lines
5.3 KiB
Vue

<script setup>
import { computed, nextTick, reactive, ref } from 'vue'
import IconButton from '@/components/common/IconButton.vue'
import Refresh from '@/components/icons/Refresh.vue'
import useConnectionStore from 'stores/connections.js'
import { map, uniqBy } from 'lodash'
import { useI18n } from 'vue-i18n'
import Delete from '@/components/icons/Delete.vue'
import dayjs from 'dayjs'
const connectionStore = useConnectionStore()
const i18n = useI18n()
const data = reactive({
loading: false,
server: '',
keyword: '',
history: [],
})
const filterServerOption = computed(() => {
const serverSet = uniqBy(data.history, 'server')
const options = map(serverSet, ({ server }) => ({
label: server,
value: server,
}))
options.splice(0, 0, {
label: i18n.t('common.all'),
value: '',
})
return options
})
const tableRef = ref(null)
const loadHistory = () => {
data.loading = true
connectionStore
.getCmdHistory()
.then((list) => {
data.history = list || []
})
.finally(() => {
data.loading = false
tableRef.value?.scrollTo({ top: 999999 })
})
}
const cleanHistory = async () => {
$dialog.warning(i18n.t('log.confirm_clean_log'), () => {
data.loading = true
connectionStore
.cleanCmdHistory()
.then((success) => {
if (success) {
data.history = []
tableRef.value?.scrollTo({ top: 0 })
$message.success(i18n.t('common.success'))
}
})
.finally(() => {
data.loading = false
})
})
}
defineExpose({
refresh: () => nextTick().then(loadHistory),
})
</script>
<template>
<n-card
:title="$t('log.launch_log')"
:bordered="false"
class="content-container flex-box-v"
content-style="display: flex;flex-direction: column; overflow: hidden;">
<n-form :disabled="data.loading" class="flex-item" inline>
<n-form-item :label="$t('log.filter_server')">
<n-select
v-model:value="data.server"
:consistent-menu-width="false"
:options="filterServerOption"
style="min-width: 100px" />
</n-form-item>
<n-form-item :label="$t('log.filter_keyword')">
<n-input v-model:value="data.keyword" clearable placeholder="" />
</n-form-item>
<n-form-item label="&nbsp;">
<icon-button :icon="Refresh" border t-tooltip="log.refresh" @click="loadHistory" />
</n-form-item>
<n-form-item label="&nbsp;">
<icon-button :icon="Delete" border t-tooltip="log.clean_log" @click="cleanHistory" />
</n-form-item>
</n-form>
<div class="content-value fill-height flex-box-h">
<n-data-table
ref="tableRef"
:columns="[
{
title: $t('log.exec_time'),
key: 'timestamp',
defaultSortOrder: 'ascend',
sorter: 'default',
width: 180,
align: 'center',
titleAlign: 'center',
render({ timestamp }, index) {
return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
},
},
{
title: $t('log.server'),
key: 'server',
filterOptionValue: data.server,
filter(value, row) {
return value === '' || row.server === value.toString()
},
width: 150,
align: 'center',
titleAlign: 'center',
ellipsis: true,
},
{
title: $t('log.cmd'),
key: 'cmd',
titleAlign: 'center',
filterOptionValue: data.keyword,
resizable: true,
filter(value, row) {
return value === '' || !!~row.cmd.indexOf(value.toString())
},
},
{
title: $t('log.cost_time'),
key: 'cost',
width: 100,
align: 'center',
titleAlign: 'center',
render({ cost }, index) {
const ms = dayjs.duration(cost).asMilliseconds()
if (ms < 1000) {
return `${ms} ms`
} else {
return `${Math.floor(ms / 1000)} s`
}
},
},
]"
:data="data.history"
class="flex-item-expand"
flex-height />
</div>
</n-card>
</template>
<style lang="scss" scoped>
@import '@/styles/content';
.content-container {
padding: 5px;
box-sizing: border-box;
}
</style>