|
@@ -40,8 +40,8 @@
|
|
|
v-for="child in item.children"
|
|
v-for="child in item.children"
|
|
|
:key="child.key"
|
|
:key="child.key"
|
|
|
class="mcp-sidebar-child-wrap"
|
|
class="mcp-sidebar-child-wrap"
|
|
|
- @mouseenter="child.key === 'support' && (supportOpen = true)"
|
|
|
|
|
- @mouseleave="child.key === 'support' && (supportOpen = false)"
|
|
|
|
|
|
|
+ @mouseenter="child.key === 'support' && openSupportPopover($event)"
|
|
|
|
|
+ @mouseleave="child.key === 'support' && scheduleCloseSupportPopover()"
|
|
|
>
|
|
>
|
|
|
<button
|
|
<button
|
|
|
type="button"
|
|
type="button"
|
|
@@ -51,21 +51,30 @@
|
|
|
>
|
|
>
|
|
|
{{ child.label }}
|
|
{{ child.label }}
|
|
|
</button>
|
|
</button>
|
|
|
- <div v-if="child.key === 'support' && supportOpen" class="mcp-sidebar-support-popover">
|
|
|
|
|
- <img
|
|
|
|
|
- src="@/assets/images/service_WeChat.png"
|
|
|
|
|
- alt="云助手客服微信"
|
|
|
|
|
- class="mcp-sidebar-support-popover-img"
|
|
|
|
|
- />
|
|
|
|
|
- <div class="mcp-sidebar-support-popover-sub">云助手客服微信</div>
|
|
|
|
|
- </div>
|
|
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</aside>
|
|
</aside>
|
|
|
|
|
+
|
|
|
|
|
+ <Teleport to="body">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-if="supportOpen"
|
|
|
|
|
+ class="mcp-sidebar-support-popover"
|
|
|
|
|
+ :style="supportPopoverStyle"
|
|
|
|
|
+ @mouseenter="cancelCloseSupportPopover"
|
|
|
|
|
+ @mouseleave="closeSupportPopover"
|
|
|
|
|
+ >
|
|
|
|
|
+ <img
|
|
|
|
|
+ src="@/assets/images/service_WeChat.png"
|
|
|
|
|
+ alt="云助手客服微信"
|
|
|
|
|
+ class="mcp-sidebar-support-popover-img"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div class="mcp-sidebar-support-popover-sub">云助手客服微信</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Teleport>
|
|
|
</template>
|
|
</template>
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { computed, onMounted, ref, watch } from "vue";
|
|
|
|
|
|
|
+import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
|
|
import { useRoute, useRouter } from "vue-router";
|
|
import { useRoute, useRouter } from "vue-router";
|
|
|
import { getMcpServerList } from "@/api/mcp";
|
|
import { getMcpServerList } from "@/api/mcp";
|
|
|
import globalStore from "@/store/modules/global";
|
|
import globalStore from "@/store/modules/global";
|
|
@@ -76,6 +85,9 @@ const global = globalStore();
|
|
|
|
|
|
|
|
const serviceChildren = ref([]);
|
|
const serviceChildren = ref([]);
|
|
|
const supportOpen = ref(false);
|
|
const supportOpen = ref(false);
|
|
|
|
|
+const supportPopoverStyle = ref({});
|
|
|
|
|
+const supportTriggerEl = ref(null);
|
|
|
|
|
+let supportCloseTimer = null;
|
|
|
|
|
|
|
|
const menuList = computed(() => [
|
|
const menuList = computed(() => [
|
|
|
{
|
|
{
|
|
@@ -144,8 +156,53 @@ const fetchServerList = async () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+const updateSupportPopoverPosition = () => {
|
|
|
|
|
+ const el = supportTriggerEl.value;
|
|
|
|
|
+ if (!el) return;
|
|
|
|
|
+ const rect = el.getBoundingClientRect();
|
|
|
|
|
+ supportPopoverStyle.value = {
|
|
|
|
|
+ top: `${rect.top}px`,
|
|
|
|
|
+ left: `${rect.right + 12}px`,
|
|
|
|
|
+ };
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const cancelCloseSupportPopover = () => {
|
|
|
|
|
+ if (supportCloseTimer) {
|
|
|
|
|
+ clearTimeout(supportCloseTimer);
|
|
|
|
|
+ supportCloseTimer = null;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const closeSupportPopover = () => {
|
|
|
|
|
+ cancelCloseSupportPopover();
|
|
|
|
|
+ supportOpen.value = false;
|
|
|
|
|
+ supportTriggerEl.value = null;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const scheduleCloseSupportPopover = () => {
|
|
|
|
|
+ cancelCloseSupportPopover();
|
|
|
|
|
+ supportCloseTimer = setTimeout(() => {
|
|
|
|
|
+ closeSupportPopover();
|
|
|
|
|
+ }, 120);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const openSupportPopover = (event) => {
|
|
|
|
|
+ cancelCloseSupportPopover();
|
|
|
|
|
+ supportTriggerEl.value = event.currentTarget;
|
|
|
|
|
+ updateSupportPopoverPosition();
|
|
|
|
|
+ supportOpen.value = true;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
fetchServerList();
|
|
fetchServerList();
|
|
|
|
|
+ window.addEventListener("scroll", updateSupportPopoverPosition, true);
|
|
|
|
|
+ window.addEventListener("resize", updateSupportPopoverPosition);
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+onBeforeUnmount(() => {
|
|
|
|
|
+ cancelCloseSupportPopover();
|
|
|
|
|
+ window.removeEventListener("scroll", updateSupportPopoverPosition, true);
|
|
|
|
|
+ window.removeEventListener("resize", updateSupportPopoverPosition);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const getItemIcon = (item) => {
|
|
const getItemIcon = (item) => {
|
|
@@ -175,7 +232,7 @@ const handleChildClick = (child) => {
|
|
|
if (child?.key === "support") {
|
|
if (child?.key === "support") {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- supportOpen.value = false;
|
|
|
|
|
|
|
+ closeSupportPopover();
|
|
|
if (child?.id) {
|
|
if (child?.id) {
|
|
|
navigateToServer(child);
|
|
navigateToServer(child);
|
|
|
return;
|
|
return;
|
|
@@ -204,8 +261,8 @@ const handleItemClick = (item) => {
|
|
|
flex-shrink: 0;
|
|
flex-shrink: 0;
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
|
position: sticky;
|
|
position: sticky;
|
|
|
- top: 16px;
|
|
|
|
|
- max-height: calc(100vh - 32px);
|
|
|
|
|
|
|
+ top: 46px;
|
|
|
|
|
+ max-height: calc(100vh - 64px - 46px - 16px);
|
|
|
overflow-y: auto;
|
|
overflow-y: auto;
|
|
|
padding: 10px 8px 20px;
|
|
padding: 10px 8px 20px;
|
|
|
background: #FFFFFF;
|
|
background: #FFFFFF;
|
|
@@ -345,10 +402,8 @@ const handleItemClick = (item) => {
|
|
|
|
|
|
|
|
.mcp-sidebar-support-popover {
|
|
.mcp-sidebar-support-popover {
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
|
- position: absolute;
|
|
|
|
|
- top: 0;
|
|
|
|
|
- left: calc(100% + 12px);
|
|
|
|
|
- z-index: 40;
|
|
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ z-index: 2000;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
align-items: center;
|