145 lines
4.2 KiB
Vue
145 lines
4.2 KiB
Vue
<script setup lang="ts">
|
|
import {
|
|
BankOutlined,
|
|
FileTextOutlined,
|
|
LoginOutlined,
|
|
ProfileOutlined,
|
|
ShoppingOutlined,
|
|
TeamOutlined,
|
|
} from '@ant-design/icons-vue';
|
|
import { computed, onMounted, ref } from 'vue';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
|
import { clearAuthUser, logout } from '@/api/auth';
|
|
import { appConfig } from '@/config/app';
|
|
import { DEFAULT_TEMPLE_ID, CURRENT_TEMPLE_ID_KEY } from '@/api/http';
|
|
import { listTemples, type Temple } from '@/api/temples';
|
|
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
const temples = ref<Temple[]>([]);
|
|
const currentTempleId = ref(localStorage.getItem(CURRENT_TEMPLE_ID_KEY) || DEFAULT_TEMPLE_ID);
|
|
|
|
const selectedKeys = computed(() => {
|
|
const moduleName = route.meta.module;
|
|
return [typeof moduleName === 'string' ? moduleName : 'users'];
|
|
});
|
|
|
|
const breadcrumbs = computed(() => {
|
|
return route.matched
|
|
.filter((matchedRoute) => matchedRoute.meta.title)
|
|
.map((matchedRoute) => ({
|
|
path: matchedRoute.path,
|
|
title: String(matchedRoute.meta.title),
|
|
}));
|
|
});
|
|
|
|
const templeOptions = computed(() => {
|
|
return temples.value.map((temple) => ({
|
|
label: temple.name,
|
|
value: String(temple.id),
|
|
}));
|
|
});
|
|
|
|
function openRoute(path: string) {
|
|
router.push(path);
|
|
}
|
|
|
|
function changeTemple(value: string) {
|
|
localStorage.setItem(CURRENT_TEMPLE_ID_KEY, value);
|
|
currentTempleId.value = value;
|
|
window.location.reload();
|
|
}
|
|
|
|
async function submitLogout() {
|
|
await logout().catch(() => undefined);
|
|
clearAuthUser();
|
|
router.push('/login');
|
|
}
|
|
|
|
async function fetchTemples() {
|
|
temples.value = await listTemples();
|
|
if (!localStorage.getItem(CURRENT_TEMPLE_ID_KEY) && temples.value.length > 0) {
|
|
const firstTempleId = String(temples.value[0].id);
|
|
localStorage.setItem(CURRENT_TEMPLE_ID_KEY, firstTempleId);
|
|
currentTempleId.value = firstTempleId;
|
|
}
|
|
}
|
|
|
|
onMounted(fetchTemples);
|
|
</script>
|
|
|
|
<template>
|
|
<a-layout class="app-shell">
|
|
<a-layout-sider class="sidebar" :width="232">
|
|
<div class="brand">
|
|
<div class="brand-mark">F</div>
|
|
<div>
|
|
<div class="brand-name">{{ appConfig.name }}</div>
|
|
<div class="brand-subtitle">{{ appConfig.subtitle }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<a-menu
|
|
class="side-menu"
|
|
mode="inline"
|
|
theme="light"
|
|
:selected-keys="selectedKeys"
|
|
>
|
|
<a-menu-item key="temples" @click="openRoute('/temples')">
|
|
<template #icon><BankOutlined /></template>
|
|
寺院管理
|
|
</a-menu-item>
|
|
<a-menu-item key="products" @click="openRoute('/products')">
|
|
<template #icon><ShoppingOutlined /></template>
|
|
商品管理
|
|
</a-menu-item>
|
|
<a-menu-item key="orders" @click="openRoute('/orders')">
|
|
<template #icon><FileTextOutlined /></template>
|
|
订单管理
|
|
</a-menu-item>
|
|
<a-menu-item key="ritual-services" @click="openRoute('/ritual-services')">
|
|
<template #icon><ProfileOutlined /></template>
|
|
法事管理
|
|
</a-menu-item>
|
|
<a-menu-item key="users" @click="openRoute('/users')">
|
|
<template #icon><TeamOutlined /></template>
|
|
用户管理
|
|
</a-menu-item>
|
|
<a-menu-item key="todos" @click="openRoute('/todos')">
|
|
<template #icon><ProfileOutlined /></template>
|
|
Todo 管理
|
|
</a-menu-item>
|
|
</a-menu>
|
|
</a-layout-sider>
|
|
|
|
<a-layout>
|
|
<a-layout-header class="topbar">
|
|
<div />
|
|
<a-space>
|
|
<a-select
|
|
class="temple-selector"
|
|
:options="templeOptions"
|
|
:value="currentTempleId"
|
|
placeholder="选择寺院"
|
|
@change="changeTemple"
|
|
/>
|
|
<a-button type="link" @click="submitLogout">
|
|
<template #icon><LoginOutlined /></template>
|
|
退出登录
|
|
</a-button>
|
|
</a-space>
|
|
</a-layout-header>
|
|
|
|
<a-layout-content class="content">
|
|
<a-breadcrumb class="breadcrumb">
|
|
<a-breadcrumb-item v-for="item in breadcrumbs" :key="item.path">
|
|
{{ item.title }}
|
|
</a-breadcrumb-item>
|
|
</a-breadcrumb>
|
|
<router-view />
|
|
</a-layout-content>
|
|
</a-layout>
|
|
</a-layout>
|
|
</template>
|