Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 3x 3x 3x 5x 4x 4x 4x 4x 1x 1x 1x 1x 1x 1x 2x 4x 1x 2x 1x 1x 1x 2x 2x 1x 1x 1x 2x 2x 2x 1x | <script setup lang="ts">
import { computed } from "vue";
import { RouterLink, RouterView } from "vue-router";
import { useRoute, useRouter } from "vue-router";
import {
PjButton,
PjPageContainer,
PjStatusNotice,
} from "@plain-journal/ui";
import { useStaffSessionStore } from "./stores/session";
const route = useRoute();
const router = useRouter();
const session = useStaffSessionStore();
const publicLayout = computed(() => route.meta.publicLayout === true);
const roles = computed(() => session.profile?.roles ?? []);
const canCatalog = computed(() => roles.value.some((role) => ["ADMIN", "OPERATOR"].includes(role)));
const canWarehouse = computed(() => roles.value.some((role) => ["ADMIN", "WAREHOUSE"].includes(role)));
const isAdmin = computed(() => roles.value.includes("ADMIN"));
async function logout() {
try {
await session.logout();
await router.replace("/login");
} catch {
// Preserve the session until an explicit local-only choice is made.
}
}
async function clearLocal() {
session.clearLocalOnly();
await router.replace("/login");
}
</script>
<template>
<a class="pj-skip-link" href="#admin-main">跳到主要内容</a>
<main v-if="publicLayout" id="admin-main" class="pj-app-main" tabindex="-1">
<RouterView />
</main>
<div v-else class="pj-app-shell admin-shell">
<header class="admin-header">
<PjPageContainer class="admin-header__inner">
<RouterLink class="admin-brand" to="/">
<span>素简记</span>
<small>管理端</small>
</RouterLink>
<div class="admin-session">
<span>{{ session.profile?.displayName }}</span>
<small>{{ session.profile?.roles.join(" / ") }}</small>
<PjButton variant="text" :disabled="session.busy" @click="logout">退出</PjButton>
</div>
</PjPageContainer>
</header>
<PjStatusNotice
v-if="session.logoutError"
class="admin-session-warning"
tone="warning"
title="退出尚未确认"
assertive
>
<span>{{ session.logoutError }} 当前会话仍保留。</span>
<template #actions>
<PjButton variant="text" @click="clearLocal">仅清除此设备</PjButton>
</template>
</PjStatusNotice>
<div class="admin-layout">
<nav class="admin-nav" aria-label="管理端导航">
<RouterLink to="/">工作区</RouterLink>
<RouterLink v-if="canCatalog" to="/catalog">商品目录</RouterLink>
<RouterLink v-if="canWarehouse" to="/inventory">库存</RouterLink>
<RouterLink v-if="canWarehouse" to="/fulfillment">履约与退货</RouterLink>
<RouterLink v-if="isAdmin" to="/after-sales">售后审核</RouterLink>
<RouterLink v-if="canCatalog" to="/marketing">营销权益</RouterLink>
<RouterLink v-if="canCatalog" to="/chat">客服会话</RouterLink>
<RouterLink v-if="canCatalog" to="/reviews">评价治理</RouterLink>
<RouterLink v-if="isAdmin" to="/governance">补偿与对账</RouterLink>
</nav>
<main id="admin-main" class="pj-app-main" tabindex="-1">
<RouterView />
</main>
</div>
</div>
</template>
|