231 lines
4.9 KiB
Vue
231 lines
4.9 KiB
Vue
<template>
|
||
<div class="entry-page">
|
||
<section
|
||
v-for="group in visibleEntryGroupList"
|
||
:key="group.title"
|
||
class="entry-group"
|
||
>
|
||
<h2 v-text="group.title" />
|
||
<div class="entry-list" :class="group.layout">
|
||
<div
|
||
v-entrance-transition="index * 70"
|
||
v-for="(item, index) in group.entryList"
|
||
:key="item.path"
|
||
class="item"
|
||
@click="go(item.path)"
|
||
>
|
||
<div class="body">
|
||
<t-icon :name="item.icon" size="1.75rem" />
|
||
<h2 v-text="item.title" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="tips gray" v-entrance-transition="visibleEntryCount * 70">微信内打开本站可能会经常在扫码时需要授权,建议使用浏览器打开(右上角菜单,使用默认浏览器打开),并添加快捷入口到桌面。</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { NotifyAPI, useUserStore } from "timi-web-api";
|
||
import { useNavBarStore } from "@/store/navBarStore";
|
||
import { corePermissionCodes, permissionCodes } from "@/utils/permission";
|
||
|
||
defineOptions({
|
||
name: "HomeTab"
|
||
});
|
||
|
||
const router = useRouter();
|
||
const navBarStore = useNavBarStore();
|
||
const userStore = useUserStore();
|
||
const unreadNotifyCount = ref(0);
|
||
let isPageActive = true;
|
||
|
||
interface HomeEntry {
|
||
path: string;
|
||
permission: string;
|
||
icon: string;
|
||
title: string;
|
||
}
|
||
|
||
interface HomeEntryGroup {
|
||
title: string;
|
||
layout?: "customer";
|
||
entryList: HomeEntry[];
|
||
}
|
||
|
||
const entryGroupList: HomeEntryGroup[] = [
|
||
{
|
||
title: "客户管理",
|
||
layout: "customer",
|
||
entryList: [
|
||
{
|
||
path: "/management/customers/create?redirect=/customers",
|
||
permission: permissionCodes.customer.create,
|
||
icon: "edit-1",
|
||
title: "录入"
|
||
},
|
||
{
|
||
path: "/customer/registration",
|
||
permission: permissionCodes.eventRecord.create,
|
||
icon: "task-checked",
|
||
title: "登记"
|
||
},
|
||
{
|
||
path: "/customer/quick-sign-in",
|
||
permission: permissionCodes.eventRecord.create,
|
||
icon: "scan",
|
||
title: "快速扫码登记"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
title: "订单管理",
|
||
entryList: [
|
||
{
|
||
path: "/management/sales-orders",
|
||
permission: permissionCodes.salesOrder.read,
|
||
icon: "task",
|
||
title: "订单列表"
|
||
},
|
||
{
|
||
path: "/management/sales-orders/create",
|
||
permission: permissionCodes.salesOrder.create,
|
||
icon: "task-add",
|
||
title: "创建订单"
|
||
},
|
||
{
|
||
path: "/management/customer-packages/create",
|
||
permission: permissionCodes.customerPackage.create,
|
||
icon: "layers",
|
||
title: "创建套餐订单"
|
||
}
|
||
]
|
||
}
|
||
];
|
||
|
||
const visibleEntryGroupList = computed(() => entryGroupList
|
||
.map(group => ({
|
||
...group,
|
||
entryList: group.entryList.filter(item => userStore.hasPermissions(item.permission))
|
||
}))
|
||
.filter(group => group.entryList.length));
|
||
const visibleEntryCount = computed(() => visibleEntryGroupList.value.reduce((count, group) => count + group.entryList.length, 0));
|
||
const canReadNotify = computed(() => userStore.hasPermissions(corePermissionCodes.notify.read));
|
||
|
||
async function go(path: string): Promise<void> {
|
||
await router.push(path);
|
||
}
|
||
|
||
async function goNotifyList(): Promise<void> {
|
||
await router.push("/notify");
|
||
}
|
||
|
||
async function loadUnreadNotifyCount(): Promise<void> {
|
||
try {
|
||
unreadNotifyCount.value = Math.max(0, await NotifyAPI.countUnreadInternal());
|
||
} catch (error) {
|
||
unreadNotifyCount.value = 0;
|
||
console.warn("未读通知数量加载失败", error);
|
||
}
|
||
if (isPageActive) {
|
||
navBarStore.setRightBadge(unreadNotifyCount.value);
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
navBarStore.clearRight();
|
||
if (canReadNotify.value) {
|
||
navBarStore.setRightIcon("notification", goNotifyList);
|
||
navBarStore.setRightBadge(0);
|
||
await loadUnreadNotifyCount();
|
||
}
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
isPageActive = false;
|
||
navBarStore.clearRight();
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.entry-page {
|
||
gap: 2rem;
|
||
display: flex;
|
||
padding: calc(var(--app-nav-height) + 1rem) 1rem 1rem 1rem;
|
||
flex-direction: column;
|
||
|
||
.entry-group {
|
||
|
||
& + & {
|
||
margin-top: 1.5rem;
|
||
}
|
||
|
||
> h2 {
|
||
color: #52607a;
|
||
margin: 0 0 .75rem 0;
|
||
font-size: .875rem;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.entry-list {
|
||
display: grid;
|
||
gap: .875rem;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
|
||
.item {
|
||
color: #0f766e;
|
||
padding: 1rem;
|
||
display: flex;
|
||
position: relative;
|
||
text-align: center;
|
||
background: rgba(255, 255, 255, .92);
|
||
box-shadow: 0 .75rem 2rem rgba(15, 23, 42, .08);
|
||
align-items: center;
|
||
aspect-ratio: 1;
|
||
border-radius: 1.4rem;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
|
||
.body {
|
||
inset: 1rem;
|
||
display: flex;
|
||
gap: .5rem;
|
||
position: absolute;
|
||
align-items: center;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
|
||
h2 {
|
||
margin: 0;
|
||
font-size: .75rem;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
.tips {
|
||
font-size: .875rem;
|
||
margin-top: 1rem;
|
||
text-indent: 2em;
|
||
}
|
||
}
|
||
|
||
:global(html.theme-dark) {
|
||
.entry-page {
|
||
.entry-group > h2 {
|
||
color: #94a3b8;
|
||
}
|
||
|
||
.item {
|
||
background: rgba(15, 23, 42, .88);
|
||
box-shadow: 0 .75rem 2rem rgba(2, 6, 23, .32);
|
||
|
||
}
|
||
}
|
||
}
|
||
</style>
|
||
|