mirror of
https://github.com/langbot-app/LangBot.git
synced 2025-11-25 19:37:36 +08:00
feat: 日志页面
This commit is contained in:
@@ -2,17 +2,32 @@
|
||||
<v-app>
|
||||
|
||||
<v-layout>
|
||||
<v-navigation-drawer :width="160" app permanent expand-on-hover>
|
||||
<v-navigation-drawer id="navigation-drawer" :width="160" app permanent rail>
|
||||
<v-list-item id="logo-list-item">
|
||||
<template v-slot:prepend>
|
||||
<v-img src="@/assets/langbot-logo-block.png" height="32" width="32"></v-img>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-divider></v-divider>
|
||||
<v-list density="compact" nav>
|
||||
<v-list-item to="/" title="仪表盘" value="dashboard" prepend-icon="mdi-view-dashboard-outline">
|
||||
<v-list-item to="/" title="仪表盘" value="dashboard" prepend-icon="mdi-speedometer" v-tooltip="仪表盘">
|
||||
</v-list-item>
|
||||
<v-list-item to="/settings" title="配置" value="settings" prepend-icon="mdi-cog-outline">
|
||||
<v-list-item to="/settings" title="设置" value="settings" prepend-icon="mdi-toggle-switch-outline"
|
||||
v-tooltip="设置">
|
||||
</v-list-item>
|
||||
<v-list-item to="/logs" title="日志" value="logs" prepend-icon="mdi-file-outline">
|
||||
<v-list-item to="/logs" title="日志" value="logs" prepend-icon="mdi-file-outline" v-tooltip="日志">
|
||||
</v-list-item>
|
||||
<v-list-item to="/plugins" title="插件" value="plugins" prepend-icon="mdi-puzzle-outline">
|
||||
<v-list-item to="/plugins" title="插件" value="plugins" prepend-icon="mdi-puzzle-outline" v-tooltip="插件">
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<template v-slot:append>
|
||||
<div>
|
||||
<v-list density="compact" nav>
|
||||
<v-list-item id="about-list-item" title="关于" prepend-icon="mdi-cog-outline" v-tooltip="关于">
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</div>
|
||||
</template>
|
||||
</v-navigation-drawer>
|
||||
|
||||
<v-main>
|
||||
@@ -24,3 +39,28 @@
|
||||
|
||||
<script setup>
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#navigation-drawer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#logo-list-item {
|
||||
margin-left: -0.2rem;
|
||||
margin-block: 0.5rem;
|
||||
}
|
||||
|
||||
#about-list-item {
|
||||
justify-self: flex-end;
|
||||
}
|
||||
|
||||
#about-list-item:hover {
|
||||
cursor: pointer;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
#about-list-item:active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
</style>
|
||||
51
web/src/components/PageTitle.vue
Normal file
51
web/src/components/PageTitle.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<span class="title-container">
|
||||
<h2 id="page-title">{{ title }}</h2>
|
||||
<v-icon @click="refresh" id="refresh-icon" icon="mdi-refresh" />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const refresh = () => {
|
||||
emit('refresh')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#page-title {
|
||||
font-weight: 500;
|
||||
margin-left: 1.4rem;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.title-container {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
#refresh-icon {
|
||||
padding-top: 0.1rem;
|
||||
margin-left: 0.5rem;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
#refresh-icon:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#refresh-icon:active {
|
||||
color: #6c6c6c;
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<h1>Dashboard</h1>
|
||||
<PageTitle title="仪表盘" @refresh="refresh" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import PageTitle from '@/components/PageTitle.vue'
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,9 +1,102 @@
|
||||
<template>
|
||||
<h1>Logs</h1>
|
||||
<PageTitle title="日志" @refresh="refresh" />
|
||||
<v-card id="toolbar">
|
||||
<v-card-text>
|
||||
<v-switch class="toolbar-component" color="primary" :model-value="proxy.$store.state.autoRefreshLog"
|
||||
@update:model-value="proxy.$store.state.autoRefreshLog = $event" label="自动刷新"></v-switch>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-card id="log-card">
|
||||
<v-card-text id="log-card-text">
|
||||
<textarea id="log-textarea" placeholder="点击标题旁的按钮以刷新日志" v-model="logContent" readonly></textarea>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import PageTitle from '@/components/PageTitle.vue'
|
||||
import { ref, getCurrentInstance, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
const logContent = ref('')
|
||||
|
||||
const refresh = () => {
|
||||
refreshLog()
|
||||
}
|
||||
|
||||
let logPointer = {
|
||||
"start_page_number": 0,
|
||||
"start_offset": 0
|
||||
}
|
||||
|
||||
const refreshLog = () => {
|
||||
proxy.$axios.get(`${proxy.$store.state.apiBaseUrl}/logs`, {
|
||||
params: {
|
||||
start_page_number: logPointer.start_page_number,
|
||||
start_offset: logPointer.start_offset
|
||||
}
|
||||
}).then(response => {
|
||||
logContent.value += response.data.data.logs
|
||||
logPointer.start_page_number = response.data.data.end_page_number
|
||||
logPointer.start_offset = response.data.data.end_offset
|
||||
})
|
||||
}
|
||||
|
||||
let refreshLogTask = null
|
||||
onMounted(() => {
|
||||
refreshLog()
|
||||
|
||||
refreshLogTask = setInterval(() => {
|
||||
if (proxy.$store.state.autoRefreshLog) {
|
||||
refreshLog()
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(refreshLogTask)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#toolbar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 1rem;
|
||||
margin-top: 1rem;
|
||||
height: 3rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.toolbar-component {
|
||||
margin-top: 1.4rem;
|
||||
}
|
||||
|
||||
|
||||
#log-card {
|
||||
margin: 1rem;
|
||||
margin-top: 1rem;
|
||||
height: calc(100vh - 10rem);
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
|
||||
#log-textarea {
|
||||
/* height: 100%; */
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
resize: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
appearance: none;
|
||||
/* background-color: #eee; */
|
||||
}
|
||||
|
||||
#log-card-text {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +1,13 @@
|
||||
<template>
|
||||
<h1>Plugins</h1>
|
||||
<PageTitle title="插件" @refresh="refresh" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import PageTitle from '@/components/PageTitle.vue'
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<template>
|
||||
<h1>Settings</h1>
|
||||
<PageTitle title="设置" @refresh="refresh" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import PageTitle from '@/components/PageTitle.vue'
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
import vuetify from './vuetify'
|
||||
import router from '@/router'
|
||||
import store from '@/store'
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
export function registerPlugins (app) {
|
||||
app
|
||||
.use(vuetify)
|
||||
.use(router)
|
||||
.use(store)
|
||||
|
||||
app.config.globalProperties.$axios = axios
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@ import router from '@/router'
|
||||
import axios from 'axios'
|
||||
|
||||
export default createStore({
|
||||
state: {},
|
||||
state: {
|
||||
apiBaseUrl: 'http://localhost:5300/api/v1',
|
||||
autoRefreshLog: false,
|
||||
version: '0.0.1'
|
||||
},
|
||||
mutations: {},
|
||||
actions: {},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user