feat(web): migrate CRM screens to Ant Design Vue with central theme

Adopt ant-design-vue and a shared antdTheme for leads, pipeline, invoices, and shared form controls under strict single-page governance.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-18 19:39:59 +03:30
co-authored by Cursor
parent ab538b8304
commit 4abab55a6b
40 changed files with 7529 additions and 11795 deletions
+233
View File
@@ -0,0 +1,233 @@
# وضعیت دیزاین‌سیستم منتکت (Montact CRM)
سند audit وضعیت واقعی لایهٔ UI در `apps/web` — نه آرزو، نه Figma.
آخرین به‌روزرسانی: ۲۶ مهر ۱۴۰۵
**راهنما:**
- **آماده** = در کد وجود دارد و به‌طور منسجم قابل اتکا است
- **نیمه‌آماده** = وجود دارد ولی پوشش/انضباط ناقص است
- **نیست** = در کدبیس پیاده نشده
---
## خلاصهٔ اجرایی
دیزاین‌سیستم منتکت **نیمه‌آماده / در حال رشد** است: توکن‌های CSS، کلاس‌های الگوی `crm-*`، و یک کیت داخلی ۱۸تایی `Ui*` وجود دارد؛ اما API دوگانهٔ لگسی (`.btn` / `.field`)، hardcode گستردهٔ رنگ و فاصله در scoped CSS، نبود Storybook، و نبود چند primitive پرکاربرد مانع «سیستم واقعی» است.
| معیار | مقدار |
|---|---|
| امتیاز کلی آمادگی | **حدود ۵۰٪** (بازهٔ واقع‌بینانه ۴۵–۵۵٪) |
| استک UI | Vue 3 SFC + Composition API — بدون Tailwind / UI kit شخص‌ثالث |
| primitives `Ui*` | ۱۸ کامپوننت + barrel |
| adoption مستقیم در views | **۵۲ از ۷۶** (~۶۸٪) |
| تم تاریک / چندتم | نیست |
| کاتالوگ زنده (Storybook و مشابه) | نیست |
**حکم یک‌خطی:** زبان بصری teal + RTL برای CRM شکل گرفته؛ انضباط و پوشش کامپوننت هنوز به سطح design system کامل نرسیده.
---
## استک و مرز سیستم
```
tokens (main.css :root)
↓
utilities / patterns (tokens.css → .crm-*)
↓
primitives (components/ui/Ui*)
↓
domain composites (pipeline/, gamification/, nav/, …)
↓
views + layouts
```
| لایه | مسیر | نقش |
|---|---|---|
| تعریف توکن‌ها | [`apps/web/src/styles/main.css`](../apps/web/src/styles/main.css) | `:root` — رنگ، تایپو، فاصله، سایه، z-index، کنترل‌ها؛ همچنین استایل لگسی `.btn` / `.field` |
| الگوهای CRM | [`apps/web/src/styles/tokens.css`](../apps/web/src/styles/tokens.css) | utilityهای `.crm-page`, `.crm-card`, `.crm-toolbar`, … (نام فایل «tokens» است؛ تعریف توکن اینجا نیست) |
| فونت | [`apps/web/src/styles/fonts.css`](../apps/web/src/styles/fonts.css) | IRANSans FaNum خودمیزبان |
| کیت UI | [`apps/web/src/components/ui/`](../apps/web/src/components/ui/) | ۱۸ SFC + [`index.ts`](../apps/web/src/components/ui/index.ts) |
| آیکن | [`apps/web/src/components/UiIcon.vue`](../apps/web/src/components/UiIcon.vue) | بیرون از barrel `ui/` |
| شِل اپ | [`layouts/AppLayout.vue`](../apps/web/src/layouts/AppLayout.vue)، [`layouts/AdmLayout.vue`](../apps/web/src/layouts/AdmLayout.vue) | سایدبار + workspace / ادمین پلتفرم |
**وابستگی‌های UI در `package.json` وب:** فقط Vue، Vue Router، Pinia، Axios، ECharts / vue-echarts، xlsx. هیچ Element Plus / Vuetify / Naive / Headless / Tailwind نیست.
---
## ماتریس آمادگی
| لایه | وضعیت | توضیح کوتاه |
|---|---|---|
| توکن رنگ / تایپو / فاصله / سایه | **آماده** | پالت teal روی slate؛ scale فونت و spacing و shadow تعریف شده |
| مقیاس radius | **نیمه‌آماده** | همهٔ `--radius-*` (جز full) روی ۱۰px قفل‌اند — سلسله‌مراتب واقعی نیست |
| spacing کامل | **نیمه‌آماده** | `--sp-1`…`6` و `8` و `10`؛ `--sp-7` / `--sp-9` نیست |
| الگوی صفحه `crm-*` | **نیمه‌آماده** | مجموعهٔ خوب برای page/header/card/table/form؛ adoption ناقص |
| primitives `Ui*` | **نیمه‌آماده** | ۱۸ قطعهٔ کاربردی؛ چند کنترل پایهٔ فرم/فیدبک غایب |
| آیکن `UiIcon` | **آماده** | ~۷۰ آیکن stroke، `currentColor`، بدون پکیج خارجی |
| Layout اپ / ادمین | **آماده** | شِل دسکتاپ + موبایل tabbar؛ ادم جدا |
| RTL + IRANSans + جلالی | **آماده** | `dir="rtl"`، فونت فارسی، `lib/jalali.ts`، ارقام فارسی |
| Dark mode / multi-theme | **نیست** | فقط تم روشن |
| Storybook / Histoire / playground | **نیست** | اسکریپت lint وب هم placeholder است |
| Checkbox / Switch / Tabs / Toast / Tooltip / Table / DatePicker به‌عنوان `Ui*` | **نیست** | معادل‌ها اغلب ad-hoc یا دامنهٔ خاص (`JalaliDateInput` و …) |
| vue-i18n | **نیست** | متن‌ها فارسی hardcode در template |
| lint / اجبار توکن (منع hex خام) | **نیست** | رنگ و rem زیاد در scoped CSS تکرار شده |
---
## توکن‌ها (آنچه واقعاً هست)
تعریف در `:root` داخل `main.css`:
| دسته | نمونه |
|---|---|
| سطح | `--bg`, `--surface`, `--surface-subtle`, `--surface-hover` |
| متن / خط | `--ink`, `--ink-secondary`, `--muted`, `--line`, … |
| accent | `--accent` (#14b8a6) و hover/deep/soft/subtle/contrast |
| معنایی | `--danger`, `--success`, `--warning`, `--info` (+ soft/deep) |
| تایپو | `--fs-xs`…`--fs-3xl`, `--fw-*`, `--lh-*`, `--font` |
| فاصله | `--sp-1`…`--sp-6`, `--sp-8`, `--sp-10` |
| کنترل | `--control-h-sm/h/md/lg`, `--pad-modal` |
| سایه / حرکت / z | `--shadow-*`, `--transition-*`, `--z-dropdown`…`--z-toast` |
| alias لگسی | `--color-primary`, `--color-text`, `--color-border`, … |
**ضعف‌ها:** radius تخت؛ `--fw-extrabold` برابر bold؛ توکن‌های محلی در `AppLayout` (مثل `--sidebar-card`) بیرون از `:root` سراسری؛ `CHART_PALETTE` در `UiChart` تا حدی جدا از توکن‌ها.
---
## کاتالوگ کامپوننت‌های `Ui*`
منبع: barrel [`components/ui/index.ts`](../apps/web/src/components/ui/index.ts).
| کامپوننت | نقش |
|---|---|
| `UiButton` | دکمه — variant / size / loading / block |
| `UiInput` | ورودی متن — `defineModel`، prefix/suffix |
| `UiTextarea` | متن چندخطی |
| `UiSelect` | select بومی با slot برای `<option>` |
| `UiField` | برچسب + hint + error دور کنترل |
| `UiCard` | کارت با header / actions / footer |
| `UiModal` | مودال + قفل اسکرول body |
| `UiDrawer` | کشو از کنار |
| `UiBusyOverlay` | پوشش busy / progress |
| `UiPageHeader` | عنوان صفحه + lead + actions + back |
| `UiBadge` | نشان وضعیت |
| `UiPagination` | صفحه‌بندی + page size |
| `UiEmptyState` | حالت خالی |
| `UiSearch` | جستجوی ساده |
| `UiFilterBar` | نوار جستجو + پنل فیلتر |
| `UiSegmented` | کنترل segmented |
| `UiChart` | ECharts + `CHART_PALETTE` |
| `UiDropdownMenu` | منوی کشویی با trigger slot |
**مرتبط ولی خارج از barrel:** `UiIcon.vue`.
**domain composites (دیزاین‌سیستم نیستند):** پوشه‌هایی مثل `pipeline/`, `gamification/`, `dashboard/`, `routines/`, `nav/`, `person-profile/` — ترکیب ویژگی‌محور روی primitives یا استایل محلی.
---
## پترن‌های UI واقعی در پروژه
### ۱) الگوی ترجیحی (هدف فعلی)
```ts
import { UiButton, UiModal, UiPageHeader } from '@/components/ui';
```
صفحه با `.crm-page` + `UiPageHeader` / `UiFilterBar` / `UiCard` / جدول `.crm-table*`.
### ۲) الگوی موازی / لگسی
- کلاس‌های سراسری `.btn`, `.btn-ghost`, `.field` در `main.css`
- `<button>` / `<input>` خام + scoped CSS در viewهای قدیمی‌تر یا خاص (Login، Notes، adm، …)
- import مستقیم فایل به‌جای barrel در بعضی viewها (`import UiButton from '@/components/ui/UiButton.vue'`)
### ۳) الگوی غیرمستقیم
بعضی viewها خودشان `ui/` را import نمی‌کنند ولی childها می‌کنند (مثلاً `HomeView` → `components/dashboard/*` → `UiChart` / `UiButton`).
### لایه‌بندی مفهومی
```mermaid
flowchart TB
tokens[CSS_tokens_main_css]
utils[crm_utilities_tokens_css]
ui[Ui_primitives]
domain[Domain_composites]
views[Views_and_Layouts]
legacy[Legacy_btn_field]
tokens --> utils
tokens --> ui
utils --> views
ui --> domain
ui --> views
domain --> views
legacy --> views
```
---
## Adoption کمی (views)
| متریک | عدد |
|---|---:|
| کل viewهای `apps/web/src/views` | ۷۶ |
| view با import مستقیم از `components/ui` | ۵۲ (~۶۸٪) |
| view بدون import مستقیم | ۲۴ (~۳۲٪) |
### بدون import مستقیم `ui/` (ممکن است از child یا لگسی استفاده کنند)
- `ActivitiesCalendarView`, `ActivityDetailView`
- `adm/AdmAdminsView`, `AdmBillingPanel`, `AdmDashboardView`, `AdmLoginView`, `AdmOrganizationsView`, `AdmUsersView`
- `AttachmentsView`, `ConversationsView`
- `gamification/GamificationView`, `GamificationAdminView`
- `HomeView`, `InvoiceFormView`, `LeadFormPublicView`
- `LoginView`, `NotesView`, `PersonProfileView`, `PortalView`, `ProfileView`
- `ProjectCardFormView`, `QuoteFormView`, `QuotesView`, `RegisterView`
**نکتهٔ کیفیت:** حتی viewهایی که `Ui*` دارند اغلب هنوز hex/`rem` محلی در `<style scoped>` دارند؛ adoption کامپوننت ≠ انضباط توکن.
---
## ساختار پوشهٔ `components/` (خلاصه)
```
components/
├── ui/ ← primitives + index.ts (تنها barrel)
├── UiIcon.vue ← آیکن مشترک
├── activities|auth|automations|brand|dashboard|
│ gamification|nav|person-*|pipeline|routines|…
└── *.vue ← ورودی‌های متقاطع (JalaliDateInput, MoneyInput, …)
```
الگوی غالب: **Composition API** با `<script setup lang="ts">`؛ استایل scoped روی کامپوننت + مصرف `var(--…)`.
---
## شکاف‌ها و اولویت پیشنهادی
ترتیب پیشنهادی برای نزدیک‌شدن به design system واقعی (فقط نقشه — خارج از scope این سند):
1. **یک API برای دکمه/فرم** — مهاجرت تدریجی از `.btn` / `.field` به `UiButton` / `UiField` + حذف یا thin-wrapper کردن لگسی
2. **تکمیل primitives پرکاربرد** — حداقل Toast، Tabs، Checkbox/Switch، Table (یا wrapper روی الگوی `.crm-table`)
3. **اجبار توکن** — جایگزینی تدریجی hex تکراری با `var(--…)`؛ در حد ممکن rule/lint
4. **کاتالوگ زنده** — Storybook / Histoire یا یک صفحهٔ داخلی فقط برای `Ui*`
5. **تم** — فقط اگر محصول dark/multi-brand می‌خواهد؛ فعلاً پیش‌نیاز انضباط توکن است
---
## چک‌لیست «آیا design system هستیم؟»
| قابلیت | وضعیت |
|---|---|
| توکن‌های مشترک | بله |
| لایهٔ الگوی صفحه | بله (ناقص) |
| کیت primitive داخلی | بله (ناقص) |
| آیکن یکپارچه | بله |
| شِل و RTL فارسی | بله |
| پوشش اکثر صفحات | نسبتاً بله (~۶۸٪ مستقیم) |
| یک منبع حقیقت بدون لگسی موازی | خیر |
| مستند/کاتالوگ زنده | خیر |
| تم / i18n / lint توکن | خیر |
**جمع‌بندی:** پروژه یک **design language + UI kit در حال رشد** دارد، نه یک design system کامل و منضبط. برای کار روزمرهٔ فیچر کافی است؛ برای اسکیل بدون drift بصری، اولویت‌های ۱–۴ بالا ضروری‌اند.
)