perf: 优化 WebUI About 页面、侧边栏和顶栏

This commit is contained in:
Soulter
2025-05-17 13:30:33 +08:00
parent 62e70a673a
commit d57b7222b2
4 changed files with 240 additions and 105 deletions
+5 -1
View File
@@ -8,6 +8,7 @@ from quart import request
from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
from astrbot.core.db import BaseDatabase
from astrbot.core.config import VERSION
from astrbot.core.utils.io import get_dashboard_version
from astrbot.core import DEMO_MODE
@@ -46,7 +47,10 @@ class StatRoute(Route):
return f"{h}小时{m}{s}"
async def get_version(self):
return Response().ok({"version": VERSION}).__dict__
return Response().ok({
"version": VERSION,
"dashboard_version": await get_dashboard_version(),
}).__dict__
async def get_start_time(self):
return Response().ok({"start_time": self.core_lifecycle.start_time}).__dict__
@@ -78,6 +78,17 @@ function accountEdit() {
});
}
function getVersion() {
axios.get('/api/stat/version')
.then((res) => {
botCurrVersion.value = "v" + res.data.data.version;
dashboardCurrentVersion.value = res.data.data?.dashboard_version;
})
.catch((err) => {
console.log(err);
});
}
function checkUpdate() {
updateStatus.value = '正在检查更新...';
axios.get('/api/update/check')
@@ -90,8 +101,6 @@ function checkUpdate() {
} else {
updateStatus.value = res.data.message;
}
botCurrVersion.value = res.data.data.version;
dashboardCurrentVersion.value = res.data.data.dashboard_version;
dashboardHasNewVersion.value = res.data.data.dashboard_has_new_version;
})
.catch((err) => {
@@ -181,6 +190,7 @@ function updateDashboard() {
});
}
getVersion();
checkUpdate();
const commonStore = useCommonStore();
@@ -208,23 +218,29 @@ if (localStorage.getItem('change_pwd_hint') != null && localStorage.getItem('cha
<v-icon>mdi-menu</v-icon>
</v-btn>
<span style="margin-left: 16px; font-size: 24px; font-weight: 1000;">Astr<span
style="font-weight: normal;">Bot</span></span>
<div style="margin-left: 16px; display: flex; align-items: center; gap: 8px;">
<span style=" font-size: 24px; font-weight: 1000;">Astr<span style="font-weight: normal;">Bot</span>
</span>
<span style="font-size: 12px; color: #333333;">{{ botCurrVersion }}</span>
</div>
<v-spacer />
<div class="mr-4">
<small v-if="hasNewVersion">
有新版本
AstrBot 有新版本
</small>
<small v-else-if="dashboardHasNewVersion">
WebUI 有新版本
</small>
</div>
<v-dialog v-model="updateStatusDialog" width="1000">
<template v-slot:activator="{ props }">
<v-btn @click="checkUpdate(); getReleases(); getDevCommits();" class="text-primary mr-4" color="lightprimary"
<v-btn size="small" @click="checkUpdate(); getReleases(); getDevCommits();" class="text-primary mr-2" color="lightprimary"
variant="flat" rounded="sm" v-bind="props">
更新 🔄
更新
</v-btn>
</template>
<v-card>
@@ -353,8 +369,8 @@ if (localStorage.getItem('change_pwd_hint') != null && localStorage.getItem('cha
<v-dialog v-model="dialog" persistent width="700">
<template v-slot:activator="{ props }">
<v-btn class="text-primary mr-4" color="lightprimary" variant="flat" rounded="sm" v-bind="props">
账户 📰
<v-btn size="small" class="text-primary mr-4" color="lightprimary" variant="flat" rounded="sm" v-bind="props">
账户
</v-btn>
</template>
<v-card>
@@ -9,9 +9,6 @@ const customizer = useCustomizerStore();
const sidebarMenu = shallowRef(sidebarItems);
const showIframe = ref(false);
const version = ref("");
const buildVer = ref("");
const hasWebUIUpdate = ref(false);
// 默认桌面端 iframe 样式
const iframeStyle = ref({
@@ -68,9 +65,10 @@ function toggleIframe() {
showIframe.value = !showIframe.value;
}
function openIframeLink() {
function openIframeLink(url) {
if (typeof window !== 'undefined') {
window.open("https://astrbot.app", "_blank");
let url_ = url || "https://astrbot.app";
window.open(url_, "_blank");
}
}
@@ -149,25 +147,6 @@ function endDrag() {
document.removeEventListener('touchend', onTouchEnd);
}
// 获取版本和更新信息
onMounted(() => {
axios.get('/api/stat/version')
.then((res) => {
version.value = "v" + res.data.data.version;
})
.catch((err) => {
console.log(err);
});
axios.get('/api/update/check?type=dashboard')
.then((res) => {
hasWebUIUpdate.value = res.data.data.has_new_version;
buildVer.value = res.data.data.current_version;
})
.catch((err) => {
console.log(err);
});
});
</script>
<template>
@@ -186,27 +165,19 @@ onMounted(() => {
<NavItem :item="item" class="leftPadding" />
</template>
</v-list>
<div class="text-center">
<v-chip color="inputBorder" size="small"> {{ version }} </v-chip>
</div>
<div style="position: absolute; bottom: 32px; width: 100%; font-size: 13px;" class="text-center">
<v-list-item v-if="!customizer.mini_sidebar" @click="toggleIframe">
<v-btn variant="plain" size="small">
🤔 点击此处 查看/关闭 悬浮文档
</v-btn>
</v-list-item>
<small style="display: block;" v-if="buildVer">WebUI 版本: {{ buildVer }}</small>
<small style="display: block;" v-else>构建: embedded</small>
<v-tooltip text="使用 /dashboard_update 指令更新管理面板">
<template v-slot:activator="{ props }">
<small v-bind="props" v-if="hasWebUIUpdate" style="display: block; margin-top: 4px;">面板有更新</small>
</template>
</v-tooltip>
<small style="display: block; margin-top: 8px;">AGPL-3.0</small>
<div style="position: absolute; bottom: 16px; width: 100%; font-size: 13px;" class="text-center">
<v-btn style="margin-bottom: 8px;" size="small" variant="plain" v-if="!customizer.mini_sidebar" @click="toggleIframe">
官方文档
</v-btn>
<br/>
<v-btn style="margin-bottom: 8px;" size="small" variant="plain" v-if="!customizer.mini_sidebar" @click="openIframeLink('https://github.com/AstrBotDevs/AstrBot')">
GitHub
</v-btn>
<br/>
</div>
</v-navigation-drawer>
<!-- 优化后的悬浮 iframe -->
<div
v-if="showIframe"
id="draggable-iframe"
+197 -53
View File
@@ -1,54 +1,84 @@
<template>
<v-card style="height: 100%;">
<v-card-text style="padding: 0; height: 100%; overflow-y: auto;">
<div
style="display: flex; justify-content: center; align-items: center; height: 100%; flex-direction: column;">
<div @click="selectedLogo = selectedLogo == 0 ? 1 : 0" style="height: 300px;">
<img v-if="selectedLogo == 0" width="300" src="@/assets/images/logo-waifu.png" alt="AstrBot Logo"
class="fade-in">
<img v-if="selectedLogo == 1" width="300" src="@/assets/images/logo-normal.svg" alt="AstrBot Logo"
class="fade-in">
</div>
<v-card style="height: 100%;" elevation="0" class="bg-surface">
<v-card-text style="padding: 0; height: 100%; overflow-y: hidden;">
<div class="about-wrapper">
<!-- Hero Section -->
<section class="hero-section">
<div class="logo-title-container">
<div @click="selectedLogo = selectedLogo == 0 ? 1 : 0" class="logo-container">
<img v-if="selectedLogo == 0" width="280" src="@/assets/images/logo-waifu.png" alt="AstrBot Logo" class="fade-in">
<img v-if="selectedLogo == 1" width="280" src="@/assets/images/logo-normal.svg" alt="AstrBot Logo" class="fade-in">
</div>
<div class="title-container">
<h1 class="text-h2 font-weight-bold">AstrBot</h1>
<p class="text-subtitle-1" style="color: #777;">A project out of interests and loves </p>
<div class="action-buttons">
<v-btn @click="open('https://github.com/Soulter/AstrBot')"
color="primary" variant="elevated" prepend-icon="mdi-star">
Star 这个项目! 🌟
</v-btn>
<v-btn class="ml-4" @click="open('https://github.com/Soulter/AstrBot/issues')"
color="secondary" variant="elevated" prepend-icon="mdi-comment-question">
提交 Issue
</v-btn>
</div>
</div>
</div>
</section>
<h1 class="mt-8">AstrBot</h1>
<!-- Contributors Section -->
<section class="contributors-section">
<v-container>
<v-row justify="center" align="center">
<v-col cols="12" md="6" class="pr-md-8 contributors-info">
<h2 class="text-h4 font-weight-medium">贡献者</h2>
<p class="mb-4 text-body-1" style="color: #777;">
本项目由众多开源社区成员共同维护感谢每一位贡献者的付出
</p>
<p class="text-body-1" style="color: #777;">
<a href="https://github.com/Soulter/AstrBot/graphs/contributors" class="text-decoration-none custom-link">查看 AstrBot 贡献者</a>
</p>
</v-col>
<v-col cols="12" md="6">
<v-card variant="outlined" class="overflow-hidden" elevation="2">
<v-img
alt="Active Contributors of Soulter/AstrBot"
src="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors/thumbnail.png?repo_id=575865240&limit=365&image_size=auto&color_scheme=light">
</v-img>
</v-card>
</v-col>
</v-row>
</v-container>
</section>
<span class="mt-2" style="color: #777;">A project out of interests and loves </span>
<span style="color: #777; margin-left: 32px; margin-right: 32px" class="mt-4">By <a
href="https://soulter.top">Soulter</a>, <a
href="https://github.com/Soulter/AstrBot/graphs/contributors">AstrBot Contributors</a>
and <a href="https://github.com/Soulter/AstrBot_Plugins_Collection/graphs/contributors">AstrBot
Plugin Authors</a>
</span>
<!-- Copy-paste in your Readme.md file -->
<img style="margin-top: 16px; width: 50%; max-width: 500px; margin-left: 32px; margin-right: 32px"
alt="Active Contributors of Soulter/AstrBot - Last 28 days"
src="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors/thumbnail.png?repo_id=575865240&limit=365&image_size=auto&color_scheme=light">
<img style="margin-top: 16px; width: 50%; max-width: 500px; margin-left: 32px; margin-right: 32px"
alt="Active Contributors of Soulter/AstrBot - Last 28 days"
src="https://next.ossinsight.io/widgets/official/analyze-repo-stars-map/thumbnail.png?activity=stars&repo_id=575865240&image_size=auto&color_scheme=light
">
<!-- Made with [OSS Insight](https://ossinsight.io/) -->
<v-btn class="text-primary mt-8" @click="open('https://github.com/Soulter/AstrBot')"
color="lightprimary" variant="flat" rounded="sm">
Star 这个项目! 🌟
</v-btn>
<v-btn class="text-primary mt-4" @click="open('https://github.com/Soulter/AstrBot/issues')"
color="lightprimary" variant="flat" rounded="sm">
有使用问题或者功能建议提交 Issue
</v-btn>
<!-- Stats Section -->
<section class="stats-section">
<v-container>
<v-row justify="center" align="center" class="flex-md-row-reverse">
<v-col cols="12" md="6" class="pl-md-8 stats-info">
<h2 class="text-h4 font-weight-medium">全球部署</h2>
<div class="license-container mt-8">
<img v-bind="props" src="https://www.gnu.org/graphics/agplv3-with-text-100x42.png" style="cursor: pointer;"/>
<p class="text-caption mt-2" style="color: #777;">AstrBot 采用 AGPL v3 协议开源</p>
</div>
</v-col>
<v-col cols="12" md="6">
<v-card variant="outlined" class="overflow-hidden" elevation="2">
<v-img
alt="Stars Map of Soulter/AstrBot"
src="https://next.ossinsight.io/widgets/official/analyze-repo-stars-map/thumbnail.png?activity=stars&repo_id=575865240&image_size=auto&color_scheme=light">
</v-img>
</v-card>
</v-col>
</v-row>
</v-container>
</section>
</div>
</v-card-text>
</v-card>
</template>
<script>
export default {
name: 'AboutPage',
@@ -64,21 +94,135 @@ export default {
}
}
}
</script>
<style>
@keyframes fadeIn {
from {
opacity: 0;
}
<style scoped>
.about-wrapper {
min-height: 100%;
}
to {
opacity: 1;
}
.hero-section {
padding: 40px 20px;
background: linear-gradient(to right bottom, rgba(255,255,255,0.7), rgba(240,240,250,0.3));
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.logo-title-container {
display: flex;
align-items: center;
flex-direction: row;
max-width: 900px;
gap: 20px;
}
.logo-container {
cursor: pointer;
transition: all 0.3s ease;
flex-shrink: 0;
}
.logo-container:hover {
transform: scale(1.05);
}
.title-container {
text-align: left;
}
.contributors-section, .stats-section {
padding: 60px 20px;
}
.contributors-section {
background-color: #f9f9fb;
}
.contributors-info, .stats-info {
display: flex;
flex-direction: column;
justify-content: center;
}
.custom-link {
display: inline-block;
padding: 5px 0;
position: relative;
color: var(--v-primary-base);
font-weight: 500;
}
.custom-link::after {
content: '';
position: absolute;
width: 100%;
transform: scaleX(0);
height: 2px;
bottom: 0;
left: 0;
background-color: var(--v-primary-base);
transform-origin: bottom right;
transition: transform 0.25s ease-out;
}
.custom-link:hover::after {
transform: scaleX(1);
transform-origin: bottom left;
}
.license-container {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.action-buttons {
display: flex;
margin-top: 24px;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.2s ease-in-out;
}
@media (max-width: 960px) {
.logo-title-container {
flex-direction: column;
text-align: center;
}
.title-container {
text-align: center;
}
.action-buttons {
justify-content: center;
}
.license-container {
align-items: center;
}
.contributors-section, .stats-section {
padding: 40px 20px;
}
}
@media (max-width: 600px) {
.action-buttons {
flex-direction: column;
gap: 12px;
}
.action-buttons .v-btn + .v-btn {
margin-left: 0 !important;
}
}
</style>