This commit is contained in:
2026-05-18 20:02:16 +08:00
parent 1565c4735f
commit 74cf99289f
14 changed files with 2250 additions and 237 deletions
@@ -1,9 +1,10 @@
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { LoaderCircle, RefreshCcw } from "lucide-vue-next";
import { LoaderCircle, PanelRight, RefreshCcw } from "lucide-vue-next";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
import Tabs from "@/components/ui/tabs/Tabs.vue";
import TabsList from "@/components/ui/tabs/TabsList.vue";
import TabsTrigger from "@/components/ui/tabs/TabsTrigger.vue";
@@ -20,6 +21,17 @@ const configStore = useConfigStore();
const loading = ref(false);
const loadError = ref("");
const isExecuting = ref(false);
const isMobileLayout = ref(false);
const isResultSheetOpen = ref(false);
let mediaQuery: MediaQueryList | null = null;
const updateMobileLayout = () => {
isMobileLayout.value = mediaQuery?.matches ?? false;
if (!isMobileLayout.value) {
isResultSheetOpen.value = false;
}
};
const tabs = [
{ label: "装备", key: "equipment" },
@@ -34,6 +46,8 @@ const activeTab = computed(() => {
return "equipment";
});
const showGlobalResultPanel = computed(() => activeTab.value !== "equipment");
const loadCharacter = async () => {
loading.value = true;
loadError.value = "";
@@ -53,6 +67,9 @@ const switchTab = (tab: (typeof tabs)[number]["key"]) => {
onMounted(() => {
loadCharacter();
window.addEventListener("beforeunload", configStore.saveConfig);
mediaQuery = window.matchMedia("(max-width: 1279px)");
updateMobileLayout();
mediaQuery.addEventListener("change", updateMobileLayout);
});
watch(
@@ -62,6 +79,12 @@ watch(
},
);
watch(showGlobalResultPanel, (show) => {
if (!show) {
isResultSheetOpen.value = false;
}
});
const stopConfigWatch = watch(
() => JSON.stringify(configStore.config),
async () => {
@@ -79,6 +102,7 @@ const stopConfigWatch = watch(
onUnmounted(() => {
stopConfigWatch();
mediaQuery?.removeEventListener("change", updateMobileLayout);
window.removeEventListener("beforeunload", configStore.saveConfig);
configStore.saveConfig();
});
@@ -89,15 +113,12 @@ onUnmounted(() => {
<Card class="flex-none">
<CardHeader>
<CardTitle class="flex items-center justify-between">
<span>角色配置 · {{ alter }}</span>
<span>角色配置</span>
<Button variant="outline" size="sm" :disabled="loading" @click="loadCharacter">
<RefreshCcw :class="{ 'animate-spin': loading }" />
刷新
</Button>
</CardTitle>
<CardDescription
>此页面承接旧版 character 模块,逐步迁移装备/技能/打造功能。</CardDescription
>
</CardHeader>
<CardContent class="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
<Tabs :model-value="activeTab" class="gap-0">
@@ -123,13 +144,35 @@ onUnmounted(() => {
</CardContent>
</Card>
<div class="grid min-h-0 flex-1 grid-cols-1 gap-4 xl:grid-cols-[minmax(0,1fr)_22rem]">
<div
:class="[
'grid min-h-0 flex-1 grid-cols-1 gap-4',
showGlobalResultPanel ? 'xl:grid-cols-[minmax(0,1fr)_24rem]' : 'xl:grid-cols-1',
]"
>
<div class="min-w-0 overflow-hidden">
<router-view />
</div>
<aside class="min-h-0">
<aside v-if="!isMobileLayout && showGlobalResultPanel" class="min-h-0">
<ResultPanel />
</aside>
</div>
<Sheet v-if="isMobileLayout && showGlobalResultPanel" v-model:open="isResultSheetOpen">
<SheetTrigger as-child>
<Button class="fixed bottom-5 right-4 z-30 shadow-lg" size="sm">
<PanelRight class="size-4" />
查看结果
</Button>
</SheetTrigger>
<SheetContent side="bottom" class="h-[78vh] overflow-hidden px-3 pb-3">
<SheetHeader class="pb-2">
<SheetTitle>实时计算结果</SheetTitle>
</SheetHeader>
<div class="h-[calc(78vh-4.5rem)] overflow-hidden">
<ResultPanel />
</div>
</SheetContent>
</Sheet>
</section>
</template>