feat: complete admin panel and backend admin api migration
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<!--
|
||||
Replacement for legacy TheNavbarVertical.vue / TheNavbarHorizontal.vue.
|
||||
Legacy carried a Vuexy/Vuesax toolbar with a theme customizer, search overlay,
|
||||
notification dropdown, bookmarks bar and i18n switcher. Of those, only the
|
||||
pieces with real backing survive: the sidebar toggle, the page title, and the
|
||||
user dropdown with logout. The rest were template demo features.
|
||||
-->
|
||||
<a-layout-header class="the-navbar">
|
||||
<div class="nav-left">
|
||||
<a-button type="text" @click="$emit('toggle-sidebar')">
|
||||
<MenuUnfoldOutlined v-if="collapsed" />
|
||||
<MenuFoldOutlined v-else />
|
||||
</a-button>
|
||||
<span class="page-title">{{ pageTitle }}</span>
|
||||
</div>
|
||||
|
||||
<div class="nav-right">
|
||||
<a-dropdown>
|
||||
<span class="user-chip">
|
||||
<a-avatar size="small" style="background-color: #1c2d56">
|
||||
{{ initial }}
|
||||
</a-avatar>
|
||||
<span class="user-name">{{ displayName }}</span>
|
||||
</span>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="my-data" @click="router.push('/my-data')">
|
||||
اطلاعات من
|
||||
</a-menu-item>
|
||||
<a-menu-divider />
|
||||
<a-menu-item key="logout" @click="onLogout">خروج</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
</a-layout-header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons-vue';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
|
||||
defineProps<{ collapsed?: boolean }>();
|
||||
defineEmits<{ (e: 'toggle-sidebar'): void }>();
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const auth = useAuthStore();
|
||||
|
||||
const pageTitle = computed(() => (route.meta?.pageTitle as string) ?? '');
|
||||
const displayName = computed(() => auth.user?.name ?? auth.user?.fullName ?? 'کاربر');
|
||||
const initial = computed(() => displayName.value.trim().charAt(0) || 'ک');
|
||||
|
||||
function onLogout() {
|
||||
auth.logout();
|
||||
router.push('/auth/login');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.the-navbar {
|
||||
height: 61px; /* legacy ara/ant.less @layout-header-height */
|
||||
background: #fff;
|
||||
padding: 0 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.nav-left,
|
||||
.nav-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.page-title {
|
||||
font-size: 16px;
|
||||
color: #1c2d56;
|
||||
}
|
||||
.user-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<!--
|
||||
Replacement for legacy henza_admin/src/layouts/components/vertical-nav-menu/
|
||||
(VerticalNavMenu.vue + VerticalNavMenuGroup/Item/Header, ~700 lines of Vuesax-
|
||||
specific markup). Vuesax has no Vue 3 build, so the tree is rendered with
|
||||
ant-design-vue's a-menu instead.
|
||||
|
||||
What is preserved exactly: the menu DATA (navMenuItems.ts, byte-exact), the
|
||||
permission filtering rule, the header/group/item nesting, and the Farsi labels.
|
||||
What changes: the DOM/classes, because the underlying component library changed.
|
||||
-->
|
||||
<a-layout-sider
|
||||
:collapsed="collapsed"
|
||||
:trigger="null"
|
||||
collapsible
|
||||
width="260"
|
||||
class="vertical-nav-menu"
|
||||
theme="light"
|
||||
>
|
||||
<div class="nav-header">
|
||||
<span v-if="!collapsed" class="nav-title">{{ title }}</span>
|
||||
</div>
|
||||
|
||||
<a-menu
|
||||
mode="inline"
|
||||
theme="light"
|
||||
:selected-keys="selectedKeys"
|
||||
:open-keys="openKeys"
|
||||
@update:openKeys="(k: string[]) => (openKeys = k)"
|
||||
@click="onClick"
|
||||
>
|
||||
<template v-for="(node, i) in visibleMenu" :key="node.url || node.header || i">
|
||||
<!-- header node: a section divider carrying `items` -->
|
||||
<a-menu-item-group v-if="node.header" :title="node.i18n || node.header">
|
||||
<template v-for="(child, j) in visibleChildren(node.items)" :key="child.url || j">
|
||||
<a-sub-menu v-if="child.submenu" :key="subKey(child, j)">
|
||||
<template #title>{{ child.i18n || child.name }}</template>
|
||||
<a-menu-item
|
||||
v-for="(leaf, k) in visibleChildren(child.submenu)"
|
||||
:key="leaf.url || `${j}-${k}`"
|
||||
>
|
||||
{{ leaf.i18n || leaf.name }}
|
||||
</a-menu-item>
|
||||
</a-sub-menu>
|
||||
<a-menu-item v-else :key="child.url || `${j}`">
|
||||
{{ child.i18n || child.name }}
|
||||
</a-menu-item>
|
||||
</template>
|
||||
</a-menu-item-group>
|
||||
|
||||
<!-- group node -->
|
||||
<a-sub-menu v-else-if="node.submenu" :key="subKey(node, i)">
|
||||
<template #title>{{ node.i18n || node.name }}</template>
|
||||
<a-menu-item
|
||||
v-for="(leaf, k) in visibleChildren(node.submenu)"
|
||||
:key="leaf.url || `${i}-${k}`"
|
||||
>
|
||||
{{ leaf.i18n || leaf.name }}
|
||||
</a-menu-item>
|
||||
</a-sub-menu>
|
||||
|
||||
<!-- leaf node -->
|
||||
<a-menu-item v-else :key="node.url || `${i}`">
|
||||
{{ node.i18n || node.name }}
|
||||
</a-menu-item>
|
||||
</template>
|
||||
</a-menu>
|
||||
</a-layout-sider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { getMenu, type NavMenuNode } from '../navMenuItems';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
|
||||
withDefaults(defineProps<{ title?: string; collapsed?: boolean }>(), {
|
||||
title: 'هنزا گلد',
|
||||
collapsed: false,
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const users = useUsersStore();
|
||||
|
||||
/**
|
||||
* Legacy's visibility rule, from the v-if on each nav item:
|
||||
* a node with no permissionId is ALWAYS visible; otherwise it needs the rid.
|
||||
*
|
||||
* That "no permissionId = public" rule is why the banker-list and shopkeeper-list
|
||||
* items (whose permissionId is commented out in the legacy data) show for everyone.
|
||||
* Preserved deliberately — see docs/ADMIN-PORT-PLAN.md.
|
||||
*/
|
||||
function canSee(node: NavMenuNode): boolean {
|
||||
if (!node.permissionId) return true;
|
||||
return Boolean(users.hasPermission(node.permissionId));
|
||||
}
|
||||
|
||||
function visibleChildren(nodes?: NavMenuNode[]): NavMenuNode[] {
|
||||
return (nodes ?? []).filter(canSee);
|
||||
}
|
||||
|
||||
/** Hides a group whose children are all hidden, as legacy did. */
|
||||
function hasVisibleContent(node: NavMenuNode): boolean {
|
||||
if (node.header) return visibleChildren(node.items).length > 0;
|
||||
if (node.submenu) return visibleChildren(node.submenu).length > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
const visibleMenu = computed(() =>
|
||||
getMenu().filter((n) => canSee(n) && hasVisibleContent(n)),
|
||||
);
|
||||
|
||||
const subKey = (node: NavMenuNode, i: number) => `sub-${node.name ?? ''}-${i}`;
|
||||
|
||||
const selectedKeys = ref<string[]>([route.path]);
|
||||
const openKeys = ref<string[]>([]);
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
(p) => {
|
||||
selectedKeys.value = [p];
|
||||
},
|
||||
);
|
||||
|
||||
function onClick({ key }: { key: string | number }) {
|
||||
const path = String(key);
|
||||
if (path.startsWith('/') && path !== route.path) {
|
||||
router.push(path);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vertical-nav-menu {
|
||||
min-height: 100vh;
|
||||
border-left: 1px solid #f0f0f0;
|
||||
}
|
||||
.nav-header {
|
||||
height: 61px; /* legacy ara/ant.less @layout-header-height */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.nav-title {
|
||||
font-size: 18px;
|
||||
color: #1c2d56;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,6 @@
|
||||
<template>
|
||||
<!-- Ported verbatim from legacy henza_admin/src/layouts/full-page/FullPage.vue -->
|
||||
<div class="layout--full-page">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<!--
|
||||
Ported from legacy henza_admin/src/layouts/main/Main.vue (281 lines).
|
||||
Structure preserved: nav menu + navbar + breadcrumb/pageTitle header +
|
||||
routed content. Dropped as template-only or Vue-2-only: VxTour, TheCustomizer,
|
||||
vue-backtotop, and the Vuesax transition wrappers.
|
||||
-->
|
||||
<a-layout class="layout--main" :class="{ 'no-scroll': isAppPage }">
|
||||
<VerticalNavMenu :collapsed="collapsed" />
|
||||
|
||||
<a-layout>
|
||||
<TheNavbar :collapsed="collapsed" @toggle-sidebar="collapsed = !collapsed" />
|
||||
|
||||
<a-layout-content id="content-area">
|
||||
<div class="content-wrapper">
|
||||
<!-- legacy router-header: shown only when the route declares one -->
|
||||
<div v-if="breadcrumb || pageTitle" class="router-header">
|
||||
<h2 class="content-area__heading">{{ routeTitle }}</h2>
|
||||
<a-breadcrumb v-if="breadcrumb" class="breadcrumb">
|
||||
<a-breadcrumb-item v-for="(crumb, i) in breadcrumb" :key="i">
|
||||
<router-link v-if="crumb.url && !crumb.active" :to="crumb.url">
|
||||
{{ crumb.title }}
|
||||
</router-link>
|
||||
<span v-else>{{ crumb.title }}</span>
|
||||
</a-breadcrumb-item>
|
||||
</a-breadcrumb>
|
||||
</div>
|
||||
|
||||
<div class="content-area__content">
|
||||
<router-view @changeRouteTitle="changeRouteTitle" />
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import VerticalNavMenu from '../components/VerticalNavMenu.vue';
|
||||
import TheNavbar from '../components/TheNavbar.vue';
|
||||
|
||||
interface Crumb {
|
||||
title: string;
|
||||
url?: string;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
const route = useRoute();
|
||||
const collapsed = ref(false);
|
||||
|
||||
const pageTitle = computed(() => route.meta?.pageTitle as string | undefined);
|
||||
const breadcrumb = computed(() => route.meta?.breadcrumb as Crumb[] | undefined);
|
||||
// legacy meta.no_scroll -> the 'no-scroll' body class
|
||||
const isAppPage = computed(() => Boolean(route.meta?.no_scroll));
|
||||
|
||||
// legacy: views could override the heading via @changeRouteTitle
|
||||
const overriddenTitle = ref<string | undefined>(undefined);
|
||||
const routeTitle = computed(() => overriddenTitle.value ?? pageTitle.value ?? '');
|
||||
|
||||
function changeRouteTitle(title: string) {
|
||||
overriddenTitle.value = title;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
overriddenTitle.value = undefined;
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout--main {
|
||||
min-height: 100vh;
|
||||
}
|
||||
#content-area {
|
||||
padding: 16px;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
.router-header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
.content-area__heading {
|
||||
margin: 0;
|
||||
color: #1c2d56;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,650 @@
|
||||
// Ported from legacy henza_admin/src/layouts/components/vertical-nav-menu/navMenuItems.js
|
||||
//
|
||||
// Converted MECHANICALLY from the legacy file (see scratchpad/convert_menu.js) so
|
||||
// that every Farsi label, permissionId, url, slug and icon survives byte-exact.
|
||||
// The only edits are structural: the legacy `import {isBranch}` and the trailing
|
||||
// const menu = isBranch() ? branchMenu : adminMenu
|
||||
// are replaced by exporting both trees plus a getMenu() selector, so the choice
|
||||
// happens at the call site instead of at module load.
|
||||
//
|
||||
// Node shapes present in the legacy data (field census across 611 lines):
|
||||
// url x76, i18n x78, permissionId x74, slug x53, icon x33, submenu x19, header x2
|
||||
// A "header" node is a section divider carrying `items`, not `submenu`.
|
||||
//
|
||||
// Legacy quirks preserved deliberately (see docs/ADMIN-PORT-PLAN.md):
|
||||
// - two nodes have their permissionId COMMENTED OUT (banker-list, shopkeeper-list),
|
||||
// so they are visible to everyone
|
||||
// - "newsletters.newsletters" and "wallet.list" never match any granted rid (#7, #8)
|
||||
// - several nodes repeat the same permissionId or reuse another view's `name`
|
||||
import { isBranch } from '../utils';
|
||||
|
||||
export interface NavMenuNode {
|
||||
url?: string | null;
|
||||
name?: string;
|
||||
slug?: string;
|
||||
icon?: string;
|
||||
i18n?: string;
|
||||
tag?: string;
|
||||
tagColor?: string;
|
||||
permissionId?: string;
|
||||
header?: string;
|
||||
items?: NavMenuNode[];
|
||||
submenu?: NavMenuNode[];
|
||||
}
|
||||
|
||||
export const adminMenu: NavMenuNode[] = [
|
||||
{
|
||||
url: null,
|
||||
name: 'پیشخوان',
|
||||
// tag: '2',
|
||||
tagColor: 'warning',
|
||||
icon: 'HomeIcon',
|
||||
i18n: 'پیشخوان',
|
||||
permissionId:"dashboard",
|
||||
submenu: [
|
||||
{
|
||||
url: '/dashboard/ecommerce',
|
||||
name: 'eCommerce',
|
||||
slug: 'dashboard-ecommerce',
|
||||
i18n: 'آمار عمده فروشی',
|
||||
permissionId:"dashboard.omde"
|
||||
},
|
||||
{
|
||||
url: '/dashboard/analytics',
|
||||
name: 'eCommerce',
|
||||
slug: 'dashboard-ecommerce',
|
||||
i18n: 'آمار تک فروشی',
|
||||
permissionId:"dashboard.tak"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
header: 'Apps',
|
||||
icon: 'PackageIcon',
|
||||
i18n: 'کاربری',
|
||||
items: [
|
||||
{
|
||||
url: null,
|
||||
name: 'User',
|
||||
icon: 'UserIcon',
|
||||
i18n: 'اشخاص',
|
||||
permissionId:"persons",
|
||||
submenu: [
|
||||
{
|
||||
url: '/customer/add',
|
||||
name: 'AddCustomer',
|
||||
slug: 'add-customer',
|
||||
i18n: 'اضافه کردن شخص',
|
||||
permissionId:"persons.create"
|
||||
},
|
||||
{
|
||||
url: '/customer/reagent-list',
|
||||
name: 'List',
|
||||
slug: 'raegentList',
|
||||
i18n: 'لیست کارشناسان فروش',
|
||||
permissionId:"persons.list.sellers"
|
||||
},
|
||||
{
|
||||
url: '/customer/omde-list',
|
||||
name: 'List',
|
||||
slug: 'omde-customer-list',
|
||||
i18n: 'لیست مشتریان عمده',
|
||||
permissionId:"persons.list.client.omde"
|
||||
},
|
||||
{
|
||||
url: '/customer/omde-non-verified-list',
|
||||
name: 'List',
|
||||
slug: 'omde-non-verified-list',
|
||||
i18n: 'لیست مشتریان در انتظار',
|
||||
permissionId:"persons.list.client.omde"
|
||||
},
|
||||
{
|
||||
url: '/customer/omde-archived-list',
|
||||
name: 'List',
|
||||
slug: 'omde-archived-list',
|
||||
i18n: 'لیست مشتریان بایگانی',
|
||||
permissionId:"persons.list.client.omde"
|
||||
},
|
||||
{
|
||||
url: '/customer/list',
|
||||
name: 'List',
|
||||
slug: 'app-user-list',
|
||||
i18n: 'لیست مشتریان تک',
|
||||
permissionId:"persons.list.client.single"
|
||||
},
|
||||
{
|
||||
url: '/customer/banker-list',
|
||||
name: 'List',
|
||||
slug: 'banker-list',
|
||||
i18n: 'لیست بنکداران'
|
||||
// permissionId:"persons.list.client."
|
||||
},
|
||||
{
|
||||
// legacy navMenuItems.js:90 spelled this with a capital S while the route
|
||||
// is '/customer/shopkeeper-list'. Case-sensitive in vue-router 4, so the
|
||||
// menu item dead-ended at the 404 page. Lowercased to match the route.
|
||||
url: '/customer/shopkeeper-list',
|
||||
name: 'List',
|
||||
slug: 'shopkeeper-list',
|
||||
i18n: 'لیست مغازه داران حضوری'
|
||||
// permissionId:"persons.list.client."
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'Branch',
|
||||
icon: 'GridIcon',
|
||||
i18n: 'شعب',
|
||||
permissionId:"branch",
|
||||
submenu: [
|
||||
{
|
||||
url: '/branch/add',
|
||||
name: 'AddBranch',
|
||||
slug: 'add-branch',
|
||||
i18n: 'افزودن شعب',
|
||||
permissionId:"branch.create"
|
||||
},
|
||||
{
|
||||
url: '/branch/list',
|
||||
name: 'BranchList',
|
||||
slug: 'branch-list',
|
||||
i18n: 'لیست شعب',
|
||||
permissionId:"branch.list"
|
||||
},
|
||||
]
|
||||
},
|
||||
/////////////////////////////////////////////
|
||||
{
|
||||
url: null,
|
||||
name: 'Workshop',
|
||||
icon: 'GridIcon',
|
||||
i18n: 'کارگاه',
|
||||
permissionId:"workshop",
|
||||
submenu: [
|
||||
{
|
||||
url: '/workshop/add',
|
||||
name: 'AddWorkshop',
|
||||
slug: 'add-workshop',
|
||||
i18n: 'افزودن کارگاه',
|
||||
permissionId:"workshop.create"
|
||||
},
|
||||
{
|
||||
url: '/workshop/list',
|
||||
name: 'WorkshopList',
|
||||
slug: 'workshop-list',
|
||||
i18n: 'لیست کارگاه ها',
|
||||
permissionId:"workshop.list"
|
||||
},
|
||||
]
|
||||
},
|
||||
/////////////////////////////////////////////
|
||||
{
|
||||
url: null,
|
||||
name: 'eCommerce',
|
||||
icon: 'ShoppingBagIcon',
|
||||
i18n: 'محصولات',
|
||||
permissionId:"product",
|
||||
submenu: [
|
||||
{
|
||||
url: '/apps/product/add',
|
||||
name: 'AddProduct',
|
||||
slug: 'add-product',
|
||||
i18n: 'افزودن محصول',
|
||||
permissionId:"product.create"
|
||||
},
|
||||
{
|
||||
url: '/apps/product/list',
|
||||
name: 'ProductList',
|
||||
slug: 'product-list',
|
||||
i18n: 'محصولات',
|
||||
permissionId:"product.list"
|
||||
},
|
||||
{
|
||||
url: '/product/change/percent',
|
||||
name: 'changePercent',
|
||||
slug: 'change-Percent',
|
||||
i18n: 'تغییر درصد محصولات',
|
||||
permissionId:"product.percent"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'order',
|
||||
icon: 'BoxIcon',
|
||||
i18n: 'سفارش ها',
|
||||
permissionId:"order",
|
||||
submenu: [
|
||||
{
|
||||
url: '/order/create',
|
||||
name: 'orderOmdeList',
|
||||
slug: 'order-omde-list',
|
||||
i18n: 'ثبت سفارش تک',
|
||||
permissionId:"order.create"
|
||||
},
|
||||
{
|
||||
url: '/order/list',
|
||||
name: 'orderList',
|
||||
slug: 'order-list',
|
||||
i18n: 'لیست سفارش های تک',
|
||||
permissionId:"order.list"
|
||||
},
|
||||
{
|
||||
url: '/order/make',
|
||||
name: 'makeOrder',
|
||||
slug: 'order-makeOrder',
|
||||
i18n: 'سفارش های ساختنی',
|
||||
permissionId:"order.makeOrder"
|
||||
},
|
||||
{
|
||||
url: '/order/omde-list',
|
||||
name: 'orderOmdeList',
|
||||
slug: 'order-omde-list',
|
||||
i18n: 'لیست سفارش های عمده',
|
||||
permissionId:"order.omde"
|
||||
},
|
||||
{
|
||||
url: '/order/tamin-list',
|
||||
name: 'orderTaminList',
|
||||
slug: 'order-tamin-list',
|
||||
i18n: 'لیست تامین',
|
||||
permissionId:"order.tamin"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'users',
|
||||
icon: 'UserIcon',
|
||||
i18n: 'مدیران',
|
||||
permissionId:"user",
|
||||
submenu: [
|
||||
{
|
||||
url: '/permission',
|
||||
name: 'permission',
|
||||
slug: 'user-permission',
|
||||
i18n: 'دسترسی ها',
|
||||
permissionId:"user.permission"
|
||||
},
|
||||
{
|
||||
url: '/user/create',
|
||||
name: 'AddUser',
|
||||
slug: 'add-user',
|
||||
i18n: 'افزودن مدیر',
|
||||
permissionId:"user.create"
|
||||
},
|
||||
{
|
||||
url: '/user/list',
|
||||
name: 'UserList',
|
||||
slug: 'user-list',
|
||||
i18n: 'لیست مدیران',
|
||||
permissionId:"user.list"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'wallet',
|
||||
icon: 'CreditCardIcon',
|
||||
i18n: 'کیف پول',
|
||||
permissionId:"wallet",
|
||||
submenu: [
|
||||
{
|
||||
url: '/wallet',
|
||||
name: 'wallet',
|
||||
slug: 'wallet',
|
||||
i18n: 'لیست کیف پول های شارژ شده',
|
||||
permissionId:"wallet.list"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'category',
|
||||
icon: 'ListIcon',
|
||||
i18n: 'دسته بندی ها',
|
||||
permissionId:"collection",
|
||||
submenu: [
|
||||
{
|
||||
url: '/category/add',
|
||||
name: 'categoryAdd',
|
||||
slug: 'add-category',
|
||||
i18n: 'افزودن دسته بندی',
|
||||
permissionId:"collection.create"
|
||||
},
|
||||
{
|
||||
url: '/category/list',
|
||||
name: 'categoryList',
|
||||
slug: 'list-category',
|
||||
i18n: 'لیست دسته بندی ها',
|
||||
permissionId:"collection.list"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'finical',
|
||||
icon: 'DollarSignIcon',
|
||||
i18n: 'اسناد مالی',
|
||||
permissionId:"document",
|
||||
submenu: [
|
||||
{
|
||||
url: '/finical/list',
|
||||
name: 'finical_list',
|
||||
slug: 'finical_list',
|
||||
i18n: 'لیست اسناد',
|
||||
permissionId:"document.list"
|
||||
},
|
||||
{
|
||||
url: '/add/findoc',
|
||||
name: 'findoc',
|
||||
slug: 'findoc',
|
||||
i18n: 'وارد کردن سند مالی مشتری',
|
||||
permissionId:"document.create"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'report',
|
||||
icon: 'GiftIcon',
|
||||
i18n: 'تخفیفات',
|
||||
permissionId:"offers",
|
||||
submenu: [
|
||||
{
|
||||
url: '/major/promotion/tak/add',
|
||||
name: 'major_promotion_add',
|
||||
slug: 'major_promotion_add',
|
||||
i18n: 'تعریف تخفیف تک',
|
||||
permissionId:"offers.create.tak"
|
||||
},
|
||||
{
|
||||
url: '/major/promotion/autopromotion',
|
||||
name: 'major_promotion_list',
|
||||
slug: 'major_promotion_list',
|
||||
i18n: 'تخفیف اتوماتیک ',
|
||||
permissionId:"offers.autopromotion"
|
||||
},
|
||||
{
|
||||
url: '/major/promotion/add',
|
||||
name: 'major_promotion_add',
|
||||
slug: 'major_promotion_add',
|
||||
i18n: 'تعریف تخفیف عمده',
|
||||
permissionId:"offers.create"
|
||||
},
|
||||
{
|
||||
url: '/major/promotion/list',
|
||||
name: 'major_promotion_list',
|
||||
slug: 'major_promotion_list',
|
||||
i18n: 'لیست تخفیفات ',
|
||||
permissionId:"offers.list"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'report',
|
||||
icon: 'SlashIcon',
|
||||
i18n: 'استثناعات تخفیف',
|
||||
permissionId:"offersIgnore",
|
||||
url: '/major/offersIgnore',
|
||||
slug: 'offersIgnore',
|
||||
},
|
||||
|
||||
{
|
||||
url: null,
|
||||
name: 'Invoice',
|
||||
icon: 'BookIcon',
|
||||
i18n: 'فاکتور انتقال',
|
||||
permissionId:"invoice",
|
||||
submenu: [
|
||||
{
|
||||
url: '/invoice/add',
|
||||
name: 'AddInvoice',
|
||||
slug: 'add-invoice',
|
||||
i18n: 'افزودن فاکتور',
|
||||
permissionId:"invoice.create"
|
||||
},
|
||||
{
|
||||
url: '/invoice/list',
|
||||
name: 'InvoiceList',
|
||||
slug: 'invoice-list',
|
||||
i18n: 'لیست فاکتورها',
|
||||
permissionId:"invoice.list"
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
url: null,
|
||||
name: 'report',
|
||||
icon: 'FileTextIcon',
|
||||
i18n: 'گزارشات',
|
||||
permissionId:"report",
|
||||
submenu: [
|
||||
{
|
||||
url: '/report/order_item',
|
||||
name: 'report_order_item',
|
||||
slug: 'report_ordedr_item',
|
||||
i18n: 'گزارش تجمیعی سفارش و اسناد',
|
||||
permissionId:"report.order.item"
|
||||
},
|
||||
{
|
||||
url: '/report/product',
|
||||
name: 'report_product',
|
||||
slug: 'report_product',
|
||||
i18n: 'گزارش محصولات',
|
||||
permissionId:"report.product"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'cities offer percent',
|
||||
// tagColor: 'warning',
|
||||
icon: 'PercentIcon',
|
||||
i18n: 'شهر ها',
|
||||
permissionId:"cities",
|
||||
submenu: [
|
||||
{
|
||||
url: '/city/create',
|
||||
name: 'create city',
|
||||
slug: 'create_city',
|
||||
i18n: 'افزودن شهر',
|
||||
permissionId:"cities.create"
|
||||
},
|
||||
{
|
||||
url: '/city/list',
|
||||
name: 'city list',
|
||||
slug: 'city_list',
|
||||
i18n: 'لیست شهر ها',
|
||||
permissionId:"cities.list"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: '/comments',
|
||||
name: 'comments',
|
||||
// tagColor: 'warning',
|
||||
icon: 'MessageSquareIcon',
|
||||
i18n: 'دیدگاه ها',
|
||||
permissionId:"comment"
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'sms',
|
||||
icon: 'MailIcon',
|
||||
i18n: 'پیامک',
|
||||
permissionId:"sms",
|
||||
submenu: [
|
||||
{
|
||||
url: '/sms/create',
|
||||
name: 'create sms',
|
||||
slug: 'create_sms',
|
||||
i18n: 'ارسال پیامک',
|
||||
permissionId:"sms.create",
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'notify',
|
||||
icon: 'BellIcon',
|
||||
i18n: 'نوتیفیکیشن',
|
||||
permissionId:"notify",
|
||||
submenu: [
|
||||
{
|
||||
url: '/notify/create',
|
||||
name: 'create notify',
|
||||
slug: 'create_notify',
|
||||
i18n: 'ارسال نوتیفیکیشن',
|
||||
permissionId:"notify.create",
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: '/statics',
|
||||
name: 'statics',
|
||||
icon: 'BarChartIcon',
|
||||
i18n: 'آمار',
|
||||
permissionId:"statics",
|
||||
},
|
||||
{
|
||||
url: '/newsletters',
|
||||
name: 'newsletters',
|
||||
icon: 'FileTextIcon',
|
||||
i18n: 'خبرنامه',
|
||||
permissionId:"newsletters.newsletters",
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
header: 'UI',
|
||||
icon: 'LayersIcon',
|
||||
i18n: 'مدیریت',
|
||||
items: [
|
||||
{
|
||||
url: null,
|
||||
name: 'پیکر بندی',
|
||||
icon: 'SettingsIcon',
|
||||
i18n: 'پیکر بندی',
|
||||
permissionId:"config",
|
||||
submenu: [
|
||||
{
|
||||
url: '/config/manage/const',
|
||||
name: 'Const Management',
|
||||
slug: 'manage-const',
|
||||
i18n: 'مدیریت ثابت ها',
|
||||
permissionId:"config.statics"
|
||||
},
|
||||
{
|
||||
url: '/config/manage/report',
|
||||
name: 'report Management',
|
||||
slug: 'manage-report',
|
||||
i18n: 'گزارش',
|
||||
permissionId:"config.report"
|
||||
},
|
||||
{
|
||||
url: '/config/manage/wallet',
|
||||
name: 'wallet Management',
|
||||
slug: 'manage-const',
|
||||
i18n: 'مدیریت کیف پول',
|
||||
permissionId:"config.wallet"
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export const branchMenu: NavMenuNode[] = [
|
||||
{
|
||||
url: '/dashboard',
|
||||
name: 'dashboard',
|
||||
tagColor: 'warning',
|
||||
icon: 'HomeIcon',
|
||||
i18n: 'پیشخوان',
|
||||
permissionId:"dashboard",
|
||||
},
|
||||
{
|
||||
url: null,
|
||||
name: 'User',
|
||||
icon: 'UserIcon',
|
||||
i18n: 'اشخاص',
|
||||
permissionId:"persons",
|
||||
submenu: [
|
||||
{
|
||||
url: '/customer/add',
|
||||
name: 'AddCustomer',
|
||||
slug: 'add-customer',
|
||||
icon:'UserPlusIcon',
|
||||
i18n: 'اضافه کردن مشتری',
|
||||
permissionId:"persons.create"
|
||||
},
|
||||
{
|
||||
url: '/customer/list',
|
||||
name: 'List',
|
||||
icon:'UsersIcon',
|
||||
slug: 'app-user-list',
|
||||
i18n: 'لیست مشتریان ',
|
||||
permissionId:"persons.list.client.single"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: '/products',
|
||||
name: 'ProductList',
|
||||
slug: 'product-list',
|
||||
icon: 'ShoppingBagIcon',
|
||||
i18n: 'محصولات',
|
||||
permissionId:"product.list"
|
||||
},
|
||||
{
|
||||
url: '/buy/order/list',
|
||||
name: 'ProductList',
|
||||
slug: 'product-list',
|
||||
icon: 'ShoppingBagIcon',
|
||||
i18n: 'فاکتور خرید',
|
||||
permissionId:"product.list"
|
||||
},
|
||||
/*{
|
||||
url: '/buy/order/list',
|
||||
name: 'ProductList',
|
||||
slug: 'product-list',
|
||||
icon: 'ShoppingBagIcon',
|
||||
i18n: 'فاکتور خرید',
|
||||
permissionId:"product.list"
|
||||
},*/
|
||||
{
|
||||
url: null,
|
||||
name: 'order',
|
||||
icon: 'BoxIcon',
|
||||
i18n: 'سفارش ها',
|
||||
permissionId:"order",
|
||||
submenu: [
|
||||
{
|
||||
url: '/order/create',
|
||||
name: 'orderOmdeList',
|
||||
icon:'InboxIcon',
|
||||
slug: 'order-omde-list',
|
||||
i18n: 'ثبت سفارش',
|
||||
permissionId:"order.create"
|
||||
},
|
||||
{
|
||||
url: '/order/list',
|
||||
name: 'orderList',
|
||||
icon:'ListIcon',
|
||||
slug: 'order-list',
|
||||
i18n: 'لیست سفارش',
|
||||
permissionId:"order.list"
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
/** Legacy: `const menu = isBranch() ? branchMenu : adminMenu`. */
|
||||
export function getMenu(): NavMenuNode[] {
|
||||
return isBranch() ? branchMenu : adminMenu;
|
||||
}
|
||||
|
||||
export default getMenu;
|
||||
Reference in New Issue
Block a user