feat: add draggable iframe for tutorial links and enhance platform configuration UI

This commit is contained in:
Soulter
2025-02-24 13:50:07 +08:00
parent 2371c32be5
commit d587a6f64c
3 changed files with 115 additions and 10 deletions
@@ -1,16 +1,69 @@
<script setup lang="ts">
import { shallowRef } from 'vue';
import { ref, shallowRef } from 'vue';
import { useCustomizerStore } from '../../../stores/customizer';
import sidebarItems from './sidebarItem';
import NavItem from './NavItem.vue';
const customizer = useCustomizerStore();
const sidebarMenu = shallowRef(sidebarItems);
const showIframe = ref(false);
const iframeStyle = ref({
position: 'fixed',
bottom: '16px',
right: '16px',
width: '500px',
height: '400px',
border: '1px solid #ccc',
background: 'white',
resize: 'both',
overflow: 'auto',
zIndex: 10000000,
borderRadius: '8px'
});
const dragButtonStyle = {
width: '100%',
padding: '4px',
cursor: 'move',
background: '#f0f0f0',
borderBottom: '1px solid #ccc',
borderTopLeftRadius: '8px',
borderTopRightRadius: '8px'
};
function toggleIframe() {
showIframe.value = !showIframe.value;
}
let offsetX = 0;
let offsetY = 0;
let isDragging = false;
function onMouseDown(event) {
isDragging = true;
offsetX = event.clientX - event.target.parentElement.getBoundingClientRect().left;
offsetY = event.clientY - event.target.parentElement.getBoundingClientRect().top;
}
function onMouseMove(event) {
if (isDragging) {
const dm = document.getElementById('draggable-iframe');
dm.style.left = (event.clientX - offsetX) + 'px';
dm.style.top = (event.clientY - offsetY) + 'px';
}
}
function onMouseUp() {
isDragging = false;
}
</script>
<template>
<v-navigation-drawer left v-model="customizer.Sidebar_drawer" elevation="0" rail-width="80"
app class="leftSidebar" :rail="customizer.mini_sidebar">
<v-navigation-drawer left v-model="customizer.Sidebar_drawer" elevation="0" rail-width="80" app class="leftSidebar"
:rail="customizer.mini_sidebar">
<v-list class="pa-4 listitem" style="height: auto">
<template v-for="(item, i) in sidebarMenu" :key="i">
<NavItem :item="item" class="leftPadding" />
@@ -21,9 +74,9 @@ const sidebarMenu = shallowRef(sidebarItems);
</div>
<div style="position: absolute; bottom: 32px; width: 100%" class="text-center">
<v-list-item v-if="!customizer.mini_sidebar" href="https://astrbot.app/">
<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">构建: {{ buildVer }}</small>
@@ -34,11 +87,23 @@ const sidebarMenu = shallowRef(sidebarItems);
</template>
</v-tooltip>
<small style="display: block; margin-top: 8px;">© 2025 AstrBot</small>
</div>
</v-navigation-drawer>
<div v-if="showIframe"
id="draggable-iframe"
:style="iframeStyle"
@mousemove="onMouseMove"
@mouseup="onMouseUp"
@mouseleave="onMouseUp">
<div :style="dragButtonStyle" @mousedown="onMouseDown">
<v-icon icon="mdi-cursor-move" />
</div>
<iframe src="https://astrbot.app" style="width: 100%; height: calc(100% - 24px); border: none; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;"></iframe>
</div>
</template>
<script lang="ts">
+14
View File
@@ -9,6 +9,17 @@ export const useCommonStore = defineStore({
log_cache: [],
log_cache_max_len: 1000,
startTime: -1,
tutorial_map: {
"qq_official_webhook": "https://astrbot.app/deploy/platform/qqofficial/webhook.html",
"qq_official": "https://astrbot.app/deploy/platform/qqofficial/websockets.html",
"aiocqhttp": "https://astrbot.app/deploy/platform/aiocqhttp/napcat.html",
"wecom": "https://astrbot.app/deploy/platform/wecom.html",
"gewechat": "https://astrbot.app/deploy/platform/gewechat.html",
"lark": "https://astrbot.app/deploy/platform/lark.html",
"telegram": "https://astrbot.app/deploy/platform/telegram.html",
}
}),
actions: {
createWebSocket() {
@@ -39,5 +50,8 @@ export const useCommonStore = defineStore({
this.startTime = res.data.data.start_time
})
},
getTutorialLink(platform) {
return this.tutorial_map[platform]
}
}
});
+30 -4
View File
@@ -47,14 +47,29 @@
</v-card>
</v-col>
</v-row>
<v-dialog v-model="showPlatformCfg" width="700">
<v-dialog v-model="showPlatformCfg">
<v-card>
<v-card-title>
<span class="text-h4">{{ newSelectedPlatformName }} 配置</span>
</v-card-title>
<v-card-text>
<AstrBotConfig :iterable="newSelectedPlatformConfig"
:metadata="metadata['platform_group']['metadata']" metadataKey="platform" />
<v-row>
<v-col cols="12" md="6">
<AstrBotConfig :iterable="newSelectedPlatformConfig"
:metadata="metadata['platform_group']['metadata']" metadataKey="platform" />
</v-col>
<v-col cols="12" md="6">
<v-btn :loading="iframeLoading" @click="refreshIframe" variant="tonal" color="primary" style="float: right;">
<v-icon>mdi-refresh</v-icon>
刷新
</v-btn>
<iframe v-show="!iframeLoading"
:src="store.getTutorialLink(newSelectedPlatformConfig.type)"
@load="iframeLoading = false" style="width: 100%; border: none; height: 100%;">
</iframe>
</v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
@@ -66,7 +81,8 @@
</v-dialog>
<v-btn style="margin-top: 16px" class="flex-grow-1" variant="tonal" size="large" rounded="lg" color="gray" @click="showConsole = !showConsole">
<v-btn style="margin-top: 16px" class="flex-grow-1" variant="tonal" size="large" rounded="lg" color="gray"
@click="showConsole = !showConsole">
<template v-slot:default>
<v-icon>mdi-console-line</v-icon>
{{ showConsole ? '隐藏' : '显示' }}日志
@@ -91,6 +107,7 @@ import axios from 'axios';
import AstrBotConfig from '@/components/shared/AstrBotConfig.vue';
import WaitingForRestart from '@/components/shared/WaitingForRestart.vue';
import ConsoleDisplayer from '@/components/shared/ConsoleDisplayer.vue';
import { useCommonStore } from '@/stores/common';
export default {
name: 'PlatformPage',
@@ -117,6 +134,9 @@ export default {
save_message_success: "",
showConsole: false,
iframeLoading: true,
store: useCommonStore()
}
},
@@ -125,6 +145,12 @@ export default {
},
methods: {
refreshIframe() {
this.iframeLoading = true;
const iframe = document.querySelector('iframe');
console.log(iframe.src);
iframe.src = iframe.src + '?t=' + new Date().getTime();
},
getConfig() {
// 获取配置
axios.get('/api/config/get').then((res) => {