mirror of https://github.com/halo-dev/halo-admin
192 lines
4.7 KiB
Vue
192 lines
4.7 KiB
Vue
<script lang="ts" setup>
|
|
// core libs
|
|
import { computed, provide, ref, watch, watchEffect } from "vue";
|
|
import { useRoute, useRouter } from "vue-router";
|
|
|
|
// libs
|
|
import cloneDeep from "lodash.clonedeep";
|
|
|
|
// hooks
|
|
import { useThemeLifeCycle } from "../composables/use-theme";
|
|
import { useSettingForm } from "@/composables/use-setting-form";
|
|
|
|
// components
|
|
import {
|
|
IconExchange,
|
|
IconEye,
|
|
IconPalette,
|
|
VButton,
|
|
VCard,
|
|
VPageHeader,
|
|
VSpace,
|
|
VTabbar,
|
|
} from "@halo-dev/components";
|
|
import ThemeListModal from "../components/ThemeListModal.vue";
|
|
import { BasicLayout } from "@halo-dev/admin-shared";
|
|
|
|
// types
|
|
import type { FormKitSettingSpec } from "@halo-dev/admin-shared";
|
|
import type { ComputedRef, Ref } from "vue";
|
|
import type { Theme } from "@halo-dev/api-client";
|
|
|
|
interface ThemeTab {
|
|
id: string;
|
|
label: string;
|
|
route: {
|
|
name: string;
|
|
params?: Record<string, string>;
|
|
};
|
|
}
|
|
|
|
const initialTabs: ThemeTab[] = [
|
|
{
|
|
id: "detail",
|
|
label: "详情",
|
|
route: {
|
|
name: "ThemeDetail",
|
|
},
|
|
},
|
|
];
|
|
|
|
const tabs = ref<ThemeTab[]>(cloneDeep(initialTabs));
|
|
const selectedTheme = ref<Theme>({} as Theme);
|
|
const themesModal = ref(false);
|
|
const activeTab = ref("");
|
|
|
|
const { isActivated, activatedTheme, handleActiveTheme } =
|
|
useThemeLifeCycle(selectedTheme);
|
|
|
|
const settingName = computed(() => selectedTheme.value.spec?.settingName);
|
|
const configMapName = computed(() => selectedTheme.value.spec?.configMapName);
|
|
|
|
const { settings, handleFetchSettings } = useSettingForm(
|
|
settingName,
|
|
configMapName
|
|
);
|
|
|
|
provide<Ref<Theme>>("activatedTheme", activatedTheme);
|
|
provide<Ref<Theme>>("selectedTheme", selectedTheme);
|
|
provide<ComputedRef<boolean>>("isActivated", isActivated);
|
|
provide<Ref<string | undefined>>("activeTab", activeTab);
|
|
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
|
|
const handleTabChange = (id: string) => {
|
|
const tab = tabs.value.find((item) => item.id === id);
|
|
if (tab) {
|
|
router.push(tab.route);
|
|
}
|
|
};
|
|
|
|
watchEffect(async () => {
|
|
if (selectedTheme.value) {
|
|
// reset tabs
|
|
tabs.value = cloneDeep(initialTabs);
|
|
await handleFetchSettings();
|
|
|
|
if (settings.value && settings.value.spec) {
|
|
tabs.value = [
|
|
...tabs.value,
|
|
...settings.value.spec.map((item: FormKitSettingSpec) => {
|
|
return {
|
|
id: item.group,
|
|
label: item.label || "",
|
|
route: {
|
|
name: "ThemeSetting",
|
|
params: {
|
|
group: item.group,
|
|
},
|
|
},
|
|
};
|
|
}),
|
|
] as ThemeTab[];
|
|
onTabChange(route.name as string);
|
|
}
|
|
}
|
|
});
|
|
|
|
const onTabChange = (routeName: string) => {
|
|
if (routeName === "ThemeSetting") {
|
|
const tab = tabs.value.find((tab) => {
|
|
return (
|
|
tab.route.name === routeName &&
|
|
tab.route.params?.group === route.params.group
|
|
);
|
|
});
|
|
if (tab) {
|
|
activeTab.value = tab.id;
|
|
return;
|
|
}
|
|
router.push({ name: "ThemeDetail" });
|
|
return;
|
|
}
|
|
|
|
// @ts-ignore
|
|
const tab = tabs.value.find((tab) => tab.route.name === route.name);
|
|
activeTab.value = tab ? tab.id : tabs.value[0].id;
|
|
};
|
|
|
|
watch(
|
|
() => route.name,
|
|
async (newRouteName) => {
|
|
onTabChange(newRouteName as string);
|
|
}
|
|
);
|
|
</script>
|
|
<template>
|
|
<BasicLayout>
|
|
<ThemeListModal
|
|
v-model:activated-theme="activatedTheme"
|
|
v-model:selected-theme="selectedTheme"
|
|
v-model:visible="themesModal"
|
|
/>
|
|
<VPageHeader :title="selectedTheme.spec?.displayName">
|
|
<template #icon>
|
|
<IconPalette class="mr-2 self-center" />
|
|
</template>
|
|
<template #actions>
|
|
<VSpace>
|
|
<VButton size="sm" type="default" @click="themesModal = true">
|
|
<template #icon>
|
|
<IconExchange class="h-full w-full" />
|
|
</template>
|
|
切换主题
|
|
</VButton>
|
|
<VButton
|
|
v-if="!isActivated"
|
|
size="sm"
|
|
type="primary"
|
|
@click="handleActiveTheme"
|
|
>
|
|
启用
|
|
</VButton>
|
|
<VButton :route="{ name: 'ThemeVisual' }" type="secondary">
|
|
<template #icon>
|
|
<IconEye class="h-full w-full" />
|
|
</template>
|
|
可视化编辑
|
|
</VButton>
|
|
</VSpace>
|
|
</template>
|
|
</VPageHeader>
|
|
|
|
<div class="m-0 md:m-4">
|
|
<VCard :body-class="['!p-0']">
|
|
<template #header>
|
|
<VTabbar
|
|
v-model:active-id="activeTab"
|
|
:items="tabs"
|
|
class="w-full !rounded-none"
|
|
type="outline"
|
|
@change="handleTabChange"
|
|
></VTabbar>
|
|
</template>
|
|
</VCard>
|
|
<div>
|
|
<RouterView :key="activeTab" />
|
|
</div>
|
|
</div>
|
|
</BasicLayout>
|
|
</template>
|