feat: 完成移动端适配

This commit is contained in:
2025-06-29 10:11:33 +08:00
parent cae0fe371b
commit 0f03841f44
7 changed files with 96 additions and 13 deletions

View File

@@ -1,3 +1,4 @@
export { default as ChevronLeftIcon } from "./svg/heroicons/ChevronLeftIcon.svg?component";
export { default as ExclamationTriangleIcon } from "./svg/heroicons/ExclamationTriangleIcon.svg?component";
export { default as microphone } from "./svg/heroicons/MicrophoneIcon.svg?component";
export { default as PaperAirplaneIcon } from "./svg/heroicons/PaperAirplaneIcon.svg?component";

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5" />
</svg>

After

Width:  |  Height:  |  Size: 226 B

View File

@@ -1,15 +1,31 @@
<script setup lang="ts">
import { NImage } from "naive-ui";
import { ChevronLeftIcon } from "@/assets/Icons";
import logo from "@/assets/logo.png";
import { useChatStore } from "@/stores";
import { useChatStore, useLayoutStore } from "@/stores";
const chatStore = useChatStore();
const { onlineCount } = storeToRefs(chatStore);
const layoutStore = useLayoutStore();
const { hiddenLeftSidebar, simpleMode } = storeToRefs(layoutStore);
</script>
<template>
<div class="h-screen flex overflow-hidden">
<div class="flex-none w-[200px] h-full flex flex-col">
<div class="relative h-screen flex overflow-hidden">
<div
class="absolute left-0 top-0 bottom-0 z-10 flex-none w-[200px] h-full flex flex-col bg-white transition-all ease-in-out"
:class="{
'-translate-x-[200px]': hiddenLeftSidebar
}"
>
<div
@click="hiddenLeftSidebar = !hiddenLeftSidebar"
class="absolute -right-3 translate-y-1/2 top-1/2 z-20 w-[24px] h-[24px] bg-[#0094c526] rounded-full flex items-center justify-center cursor-pointer"
:class="{
'rotate-180 -right-8': hiddenLeftSidebar
}"
>
<ChevronLeftIcon class="!w-4 !h-4 text-[#777]" />
</div>
<router-link class="w-full my-6 cursor-pointer" to="/">
<NImage
class="w-full object-cover"
@@ -40,7 +56,10 @@ const { onlineCount } = storeToRefs(chatStore);
</div>
</div>
</div>
<div class="flex-1 relative">
<div
class="flex-1 relative"
:class="{ 'ml-[200px]': !hiddenLeftSidebar && !simpleMode }"
>
<RouterView />
</div>
</div>

View File

@@ -1,2 +1,3 @@
export * from "./asr_store";
export * from "./chat_store";
export * from "./layout_store";

View File

@@ -0,0 +1,44 @@
import { matchMedia } from "@/utils";
export const useLayoutStore = defineStore("layout", () => {
// 侧边栏状态
const hiddenLeftSidebar = ref(false);
// 简洁按钮
const simpleMode = ref(false);
const handleResize = () => {
matchMedia(
"sm",
() => {
hiddenLeftSidebar.value = true;
},
() => {
hiddenLeftSidebar.value = false;
}
);
matchMedia(
"536",
() => {
simpleMode.value = true;
},
() => {
simpleMode.value = false;
}
);
};
const toggleLeftSidebar = () => {
hiddenLeftSidebar.value = !hiddenLeftSidebar.value;
};
window.addEventListener("resize", handleResize);
onMounted(() => {
handleResize();
});
onUnmounted(() => {
window.removeEventListener("resize", handleResize);
});
return { hiddenLeftSidebar, toggleLeftSidebar, simpleMode };
});

View File

@@ -35,6 +35,7 @@ export const matchMedia = (
}
};
/** 获取视窗宽度 */
export const useWindowWidth = () => {
const width = ref(window.innerWidth);

View File

@@ -10,14 +10,15 @@ import {
} from "@/assets/Icons";
import UserAvatar from "@/assets/user_avatar.jpg";
import markdown from "@/components/markdown.vue";
import { useAsrStore, useChatStore } from "@/stores";
import { useAsrStore, useChatStore, useLayoutStore } from "@/stores";
const chatStore = useChatStore();
const asrStore = useAsrStore();
const { historyMessages, completing, modelList, modelInfo } =
storeToRefs(chatStore);
const asrStore = useAsrStore();
const { isRecording } = storeToRefs(asrStore);
const layoutStore = useLayoutStore();
const { hiddenLeftSidebar, simpleMode } = storeToRefs(layoutStore);
const inputData = ref("");
const scrollbarRef = ref<HTMLElement | null>(null);
@@ -93,7 +94,8 @@ onMounted(() => {
<template>
<div
class="p-8 !pr-4 h-full w-full flex flex-col gap-4 border-l-[24px] border-l-[#FAFAFA] text-base"
class="p-8 !pr-4 h-full w-full flex flex-col gap-4 border-l-[24px] border-l-[#FAFAFA] transition-all ease-in-out text-base"
:class="{ '!border-l-0': hiddenLeftSidebar || simpleMode }"
>
<!-- 历史消息区 -->
<NScrollbar ref="scrollbarRef" class="flex-1 pr-4 relative">
@@ -182,16 +184,28 @@ onMounted(() => {
</template>
<template #trigger>
<NButton :disabled="isRecording || completing" type="warning">
清除历史
<TrashIcon class="!w-4 !h-4 ml-1" />
<template v-if="!simpleMode">清除历史</template>
<TrashIcon
class="!w-4 !h-4"
:class="{
'ml-1': !simpleMode
}"
/>
</NButton>
</template>
<span>确定要清除历史消息吗?</span>
</NPopconfirm>
<NButton :disabled="completing" @click="toggleRecording">
<template v-if="!simpleMode">
{{ isRecording ? "停止输入" : "语音输入" }}
<microphone class="!w-4 !h-4 ml-1" />
</template>
<microphone
class="!w-4 !h-4"
:class="{
'ml-1': !simpleMode
}"
/>
</NButton>
<NButton
:disabled="isRecording"