feat: باشگاه امتیازات کارکنان (موتور امتیاز، جدول رتبه، فروشگاه پاداش، نشان‌ها، پنل مدیریت و گزارش ROI)

- موتور رویدادمحور با شرط، محدودیت، تأیید مدیر و idempotency
- اتصال به لید، مشتری، معامله، فعالیت، روتین، پیش‌فاکتور، فاکتور و تیکت
- صفحه /club و /club/admin، اعلان زنده امتیاز، آیتم منو
- انتقال فرم‌ساز سرنخ به ابزارها

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-10 21:28:49 +03:30
co-authored by Cursor
parent b87ebb22e0
commit 60d797f184
51 changed files with 11298 additions and 806 deletions
+28 -3
View File
@@ -9,6 +9,7 @@ import MentoLogo from '@/components/brand/MentoLogo.vue';
import QuickCreate from '@/components/QuickCreate.vue';
import OrgSwitcher from '@/components/OrgSwitcher.vue';
import NavHubPanel from '@/components/nav/NavHubPanel.vue';
import GamificationToaster from '@/components/gamification/GamificationToaster.vue';
import { NAV_HUBS, type NavHubDef, type NavHubKey } from '@/lib/nav-hubs';
import type {
ActivitySummaryDto,
@@ -49,9 +50,8 @@ function pathIn(prefixes: string[]) {
const dashboardActive = computed(() => route.path === '/');
const loyaltyActive = computed(() => pathIn(['/loyalty']));
const reportsActive = computed(() => pathIn(['/reports']));
const leadsActive = computed(() =>
pathIn(['/leads', '/settings/lead-stages', '/settings/lead-forms']),
);
const clubActive = computed(() => pathIn(['/club']));
const leadsActive = computed(() => pathIn(['/leads', '/settings/lead-stages']));
const customersActive = computed(
() => pathIn(['/contacts']) || (isMobileNav.value && leadsActive.value),
);
@@ -85,6 +85,7 @@ const toolsActive = computed(() =>
'/cheques',
'/attachments',
'/reservations',
'/settings/lead-forms',
]),
);
const settingsActive = computed(() =>
@@ -104,6 +105,7 @@ const settingsActive = computed(() =>
const moreSectionActive = computed(
() =>
routinesActive.value ||
clubActive.value ||
notesActive.value ||
conversationsActive.value ||
supportActive.value ||
@@ -539,6 +541,18 @@ onUnmounted(() => {
<span v-if="routineBadge" class="nav-badge">{{ toFaDigits(routineBadge) }}</span>
</RouterLink>
<RouterLink
v-if="moduleAllowed('gamification')"
to="/club"
class="nav-item"
title="باشگاه امتیازات"
:class="{ 'router-link-active': clubActive }"
@click="closeHub(); closeMenu()"
>
<UiIcon name="trophy" :size="collapsed ? 20 : 18" />
<span>باشگاه امتیازات</span>
</RouterLink>
<RouterLink
v-if="moduleAllowed('conversations')"
to="/conversations"
@@ -796,6 +810,7 @@ onUnmounted(() => {
<main class="content">
<RouterView />
<GamificationToaster v-if="moduleAllowed('gamification')" />
</main>
</div>
@@ -899,6 +914,16 @@ onUnmounted(() => {
<span>کارهای روتین</span>
<span v-if="routineBadge" class="nav-badge">{{ toFaDigits(routineBadge) }}</span>
</RouterLink>
<RouterLink
v-if="moduleAllowed('gamification')"
to="/club"
class="nav-item"
:class="{ 'router-link-active': clubActive }"
@click="closeHub(); closeMore()"
>
<UiIcon name="trophy" :size="18" />
<span>باشگاه امتیازات</span>
</RouterLink>
<RouterLink to="/notes" class="nav-item" @click="closeHub(); closeMore()">
<UiIcon name="document" :size="18" />
<span>یادداشت‌ها</span>