admin user and ui panel
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
# ماژول محصول (Product) — ادمین پنل
|
||||
|
||||
مستند تعریف محصول، تنوع (Variant) و ثبت اطلاعات در ادمین پنل، منطبق بر پیادهسازی فعلی.
|
||||
|
||||
مسیرهای مرتبط:
|
||||
- فرم ثبت/ویرایش: [AddProduct.vue](../apps/admin-panel/src/views/apps/product/AddProduct.vue) (هم برای ایجاد هم ویرایش استفاده میشود؛ [EditProduct.vue](../apps/admin-panel/src/views/apps/product/EditProduct.vue) صرفاً یک wrapper است)
|
||||
- لیست محصولات: [ProductList.vue](../apps/admin-panel/src/views/apps/product/ProductList.vue) و مدل جدول [productListModel.ts](../apps/admin-panel/src/views/apps/product/productListModel.ts)
|
||||
- بکاند: [admin-products.controller.ts](../apps/api/src/modules/admin-products/admin-products.controller.ts) و [admin-products.service.ts](../apps/api/src/modules/admin-products/admin-products.service.ts)
|
||||
- اسکیمای دیتابیس: [schema.prisma](../apps/api/prisma/schema.prisma) (مدلهای `Product`, `ProductVariant`, `ProductImage`)
|
||||
|
||||
---
|
||||
|
||||
## ۱. تعریف محصول (Product)
|
||||
|
||||
هر محصول یک رکورد پایه دارد که در کارت «اطلاعات پایه» و «تصاویر محصول» فرم پر میشود.
|
||||
|
||||
### ۱.۱ اطلاعات پایه
|
||||
|
||||
| فیلد فرم (فارسی) | نام در فرم/پیلود | ستون در دیتابیس | نوع | الزامی | توضیح |
|
||||
|---|---|---|---|---|---|
|
||||
| کد محصول | `product_code` | `Product.productCode` | string، یکتا (`@unique`) | خیر | SKU نمایشی؛ در فرم اعتبارسنجی نمیشود ولی در دیتابیس یکتا است |
|
||||
| نام محصول | `title` | `Product.title` | string | بله | تنها فیلد با اعتبارسنجی سمت فرم (`err.title`) |
|
||||
| نوع نمایش | `show_type` | `Product.showType` | int، پیشفرض `3` | خیر | مقادیر: `1` سایت، `2` گوشی، `3` سایت و گوشی |
|
||||
| دستهبندی | `category_id` | `Product.categoryId` (FK به `Category`) | string، اختیاری | خیر | از `GET category` پر میشود؛ عنوانها با نوع فروشگاه (`type_str`) پسوند میخورند |
|
||||
| برند | `brand_id` | `Product.brandId` (FK به `Brand`) | string، اختیاری | خیر | از `GET brand` |
|
||||
| سینیها (گروهبندی) | `ciny_ids` | جدول واسط `CollectionProduct` → مدل `Collection` | آرایه از id | خیر | چندانتخابی؛ معادل مدرن فیچر قدیمی «Ciny»، صرفاً یک تگگذاری/گروهبندی محصول است، نه چیزی مرتبط با قیمت لحظهای طلا |
|
||||
| شرح محصول (سایت) | `body_html` | `Product.description` | text | خیر | |
|
||||
| نمایش محصول | `is_active` | `Product.isActive` | boolean، پیشفرض `true` | خیر | فعال/غیرفعال بودن محصول در فروشگاه |
|
||||
|
||||
فیلدهای سیستمی که در فرم دیده نمیشوند: `id` (cuid)، `createdAt`.
|
||||
|
||||
> فیلدهای نسخه قدیمی که عمداً حذف شدهاند (چون ستون معادل در اسکیمای جدید ندارند): `delivery_type`, `message_long_delivery`, `offer_day`, `has_warranty`, `is_exist`, `tags`، و فیلدهای رنگ/اجرت ریالی در تنوع. طبق کامنت بالای فایل فرم، این تصمیم آگاهانه بوده — داده جمعآوری و بیصدا دور ریخته نمیشود.
|
||||
|
||||
### ۱.۲ تصاویر محصول
|
||||
|
||||
محصول به ازای هر تصویر یک رکورد `ProductImage` دارد که با فیلد `role` مشخص میشود کدام یک از ۴ اسلات قدیمی است:
|
||||
|
||||
| بخش فرم (فارسی) | `ProductImageRole` | تعداد | فیلد پیلود |
|
||||
|---|---|---|---|
|
||||
| تصویر شاخص | `FEATURED` | تک | `indicator_id` |
|
||||
| تصویر شاخص موبایل | `FEATURED_MOBILE` | تک | `mobile_pic` |
|
||||
| گالری تصاویر سایت | `GALLERY` (پیشفرض) | چندتایی | `images` |
|
||||
| گالری تصاویر موبایل | `GALLERY_MOBILE` | چندتایی | `images_mobile` |
|
||||
|
||||
آپلود از طریق کامپوننت `ImageUploadInput` و اندپوینت عمومی `file/create` انجام میشود (همان اندپوینتی که برای آپلود دستهبندی/اسلایدر/آواتار هم استفاده میشود). فیلد `imageBody` (کپشن هر تصویر گالری در نسخه قدیمی) معادلی در دیتابیس ندارد و حذف شده.
|
||||
|
||||
---
|
||||
|
||||
## ۲. کارکرد واریانت (تنوع محصول)
|
||||
|
||||
هر محصول میتواند چند «تنوع» (`ProductVariant`) داشته باشد — مثلاً وزنهای مختلف یک مدل طلا. مدیریت واریانتها **درون همان فرم محصول** و بهصورت یک جدول اینلاین با مودال افزودن/ویرایش انجام میشود؛ واریانتها تا زمان «ثبت اطلاعات» فقط در حافظه (state) نگه داشته میشوند و همراه با کل محصول به سرور ارسال میگردند.
|
||||
|
||||
### ۲.۱ فیلدهای واریانت
|
||||
|
||||
| عنوان در مودال | نام فیلد | ستون دیتابیس | نوع | توضیح |
|
||||
|---|---|---|---|---|
|
||||
| عنوان | `title` | `ProductVariant.title` | string، الزامی | تنها فیلد با اعتبارسنجی (`عنوان تنوع الزامی است`) |
|
||||
| وزن | `grams` | `ProductVariant.rashWeightGrams` | Decimal(14,4) | وزن پایه/خام پیش از احتساب اجرت («rash weight») |
|
||||
| اجرت درصدی | `percentage_pay` | `ProductVariant.defaultWagePercent` | Decimal(6,3) | درصد اجرت پیشفرض روی وزن پایه |
|
||||
| تعداد | `qty` | `ProductVariant.qty` | int، پیشفرض `0` | موجودی انبار |
|
||||
| فعال | `is_active` | `ProductVariant.isActive` | boolean، پیشفرض `true` | |
|
||||
| پیش سفارش | `is_pre_order` | `ProductVariant.isPreOrder` | boolean، پیشفرض `false` | اگر `true` باشد، حتی با موجودی صفر قابل سفارش است |
|
||||
|
||||
فیلدهای دیگر مدل `ProductVariant` که در فرم نیستند: `sku` (یکتا)، `id`. فیلد رنگ و اجرت ریالی نسخه قدیمی حذف شدهاند (بدون ستون معادل).
|
||||
|
||||
> قاعدهی سبد خرید: اگر `qty = 0` و `isPreOrder = false` باشد، واریانت قابل افزودن به سبد نیست (منطق در `apps/admin-panel/src/stores/cart.ts`).
|
||||
|
||||
### ۲.۲ رفتار UI جدول تنوعها
|
||||
|
||||
- ستونها: عنوان، وزن، اجرت درصدی، تعداد، فعال (تگ سبز/قرمز)، پیش سفارش (تگ آبی/خالی)، عملیات.
|
||||
- **افزودن تنوع**: دکمه بالای جدول → باز کردن مودال خالی با کلید موقت `__key` (برای ردیابی ردیف پیش از ذخیره در سرور).
|
||||
- **ویرایش تنوع**: آیکون ویرایش هر ردیف → پر کردن مودال با مقادیر همان ردیف.
|
||||
- **حذف تنوع**: آیکون حذف → صرفاً از آرایهی حافظه حذف میشود؛ حذف واقعی از دیتابیس زمانی رخ میدهد که فرم اصلی «ثبت اطلاعات» شود.
|
||||
- کل بخش تنوعها پشت پرمیشن است (زیر بخش «ثبت اطلاعات» دقیقتر شرح داده شده).
|
||||
|
||||
---
|
||||
|
||||
## ۳. ثبت اطلاعات
|
||||
|
||||
### ۳.۱ فرم ایجاد/ویرایش
|
||||
|
||||
- یک فرم واحد (`AddProduct.vue`) هم برای ایجاد و هم ویرایش به کار میرود؛ تشخیص حالت از روی وجود `route.params.id`.
|
||||
- **اعتبارسنجی سمت کلاینت**: فقط «نام محصول» (`title`) الزامی است؛ در سطح واریانت فقط «عنوان» الزامی است. سایر فیلدها اختیاریاند.
|
||||
- **دکمه ارسال**: «ثبت اطلاعات» → `handleSubmit`.
|
||||
|
||||
### ۳.۲ اندپوینتها
|
||||
|
||||
| حالت | متد | مسیر |
|
||||
|---|---|---|
|
||||
| ایجاد محصول جدید | `POST` | `product/create` |
|
||||
| ویرایش محصول موجود | `PUT` | `product/update/:id` |
|
||||
| نمایش یک محصول (پر کردن فرم ویرایش) | `GET` | `product/show/:id` |
|
||||
| لیست برندها | `GET` | `brand` |
|
||||
| لیست دستهبندیها | `POST` | `category` |
|
||||
| لیست سینیها/کالکشنها | `GET` | `admin/products/collections` |
|
||||
|
||||
### ۳.۳ ساختار پیلود ارسالی
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "...",
|
||||
"product_code": "...",
|
||||
"show_type": 3,
|
||||
"category_id": "...",
|
||||
"brand_id": "...",
|
||||
"ciny_ids": ["..."],
|
||||
"body_html": "...",
|
||||
"is_active": true,
|
||||
"indicator_id": "url|null",
|
||||
"mobile_pic": "url|null",
|
||||
"cats": ["category_id"],
|
||||
"images": ["url", "..."],
|
||||
"images_mobile": ["url", "..."],
|
||||
"variants": [
|
||||
{
|
||||
"id": "فقط در ویرایش واریانت موجود",
|
||||
"title": "...",
|
||||
"grams": 0,
|
||||
"percentage_pay": 0,
|
||||
"qty": 0,
|
||||
"is_active": true,
|
||||
"is_pre_order": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
نکات مهم:
|
||||
- `cats` مشتق از `category_id` است (آرایهای تکعضوی یا خالی) — یک artifact از انتقال ساختار قدیمی چند-دستهای.
|
||||
- `images` معادل گالری سایت و `images_mobile` معادل گالری موبایل است؛ تصاویر شاخص جدا (`indicator_id`, `mobile_pic`) ارسال میشوند.
|
||||
- کل آرایه `variants` هر بار با کل درخواست ارسال میشود (نه اندپوینت جداگانه)؛ بکاند مسئول تطبیق/ایجاد/بهروزرسانی ردیفها بر اساس وجود یا نبود `id` است.
|
||||
|
||||
### ۳.۴ بازخورد به کاربر
|
||||
|
||||
- موفق: پیام `اطلاعات با موفقیت به ثبت رسید.` و ریدایرکت به `/apps/product/list`.
|
||||
- خطا: پیام خطای برگشتی از سرور (`e.response.data.message`) یا پیام پیشفرض `خطا در ثبت اطلاعات.`
|
||||
- در حین ارسال، کل فرم پشت `a-spin` (لودینگ) قفل میشود.
|
||||
|
||||
### ۳.۵ پرمیشنهای مرتبط با ثبت/مدیریت واریانت
|
||||
|
||||
| کلید پرمیشن | کنترل میکند |
|
||||
|---|---|
|
||||
| `product.list.variants` | نمایش کل بخش «تنوعها» در فرم محصول |
|
||||
| `product.list.variants.view` | مشاهده (تعریفشده در `permissionConst.ts`؛ در UI فعلی فرم جداگانه چک نشده) |
|
||||
| `product.list.variants.add` | نمایش دکمه «افزودن تنوع» |
|
||||
| `product.list.variants.edit` | نمایش آیکون ویرایش هر ردیف تنوع |
|
||||
| `product.list.variants.remove` | نمایش آیکون حذف هر ردیف تنوع |
|
||||
|
||||
ثبت خودِ محصول (فرم اصلی) پرمیشن جداگانهای در این فایل چک نمیکند — دسترسی به صفحه از طریق روتینگ/منو کنترل میشود.
|
||||
|
||||
---
|
||||
|
||||
## ۴. لیست محصولات (خلاصه، برای زمینه)
|
||||
|
||||
جدول لیست (`admin/products/list`) این ستونها را نشان میدهد: کد، تصویر محصول، نام محصول، برند، دستهبندی، کد محصول، نوع نمایش (با فیلتر انتخابی روی مقادیر ۱/۲/۳)، عملیات. تعریف کامل در [productListModel.ts](../apps/admin-panel/src/views/apps/product/productListModel.ts).
|
||||
Reference in New Issue
Block a user