43 KiB
📝 BackOffice — Changelog
آخرین بروزرسانی: اسفند ۱۴۰۴ (February 17, 2026)
🏷 فاز ۱۵ — Production Deploy + فیکس CI/CD Cross-Deploy (اسفند ۱۴۰۴)
هدف: دیپلوی به سرور Production و رفع باگ cross-deploy
۱۵.۱ — Merge به برنچ production ✅
- کامیت:
4454b8d— mergekub-stage→production - ریموت:
kub-stage(Gitea)
۱۵.۲ — فیکس باگ Cross-Deploy ✅
- مشکل: Gitea Act Runner همه workflowهای
.gitea/workflows/را اجرا میکرد — بدون توجه بهbranches:filter - عارضه: push به
productionباعث دیپلوی همزمان به staging و production میشد - رفع: حذف فایلهای workflow staging از برنچ production
- فایل حذف شده:
.gitea/workflows/deploy.yml(staging) از برنچ production
۱۵.۳ — بروزرسانی Proto به v0.0.179 ✅
- تغییر:
Foursat.CMSMicroservice.Protobuf→0.0.179 - فایل:
BackOffice.csproj
🏷 فاز ۱۴ — فیکس Docker Build + Deployment (بهمن ۱۴۰۴)
هدف: رفع مشکلات Docker build و CI/CD pipeline
۱۴.۱ — تغییر به NuGet Package ✅
- مشکل:
ProjectReferenceبه../../../CMS/src/CMSMicroservice.Protobuf/خارج از Docker build context بود - رفع: تغییر به
PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.178" - فایل:
BackOffice.csproj
۱۴.۲ — حذف COPY libs/ از Dockerfile ✅
- مشکل:
COPY ["libs/", "libs/"]فیل میشد —libs/خارج از build context - رفع: حذف خط — دیگه نیازی به DLLهای BFF نیست
- فایل:
Dockerfile
۱۴.۳ — تغییر nginx:alpine به رجیستری لوکال ✅
- مشکل:
FROM nginx:alpineاز Docker Hub → TLS handshake timeout - رفع:
FROM 194.5.195.53:32082/nginx:alpine - فایل:
Dockerfile
۱۴.۴ — اضافه شدن SERVER_PASSWORD secret ✅
- مشکل: مرحله Deploy to Kubernetes با
Permission deniedفیل میشد - رفع: سکرت
SERVER_PASSWORDبه ریپو Gitea اضافه شد (BackOffice + FrontOffice)
🏷 فاز ۱۳ — بهبودهای UI بکآفیس (بهمن ۱۴۰۴)
هدف: رفع مشکلات بصری، بهبود UX فرمها و ناوبری
۱۳.۱ — فیکس کامپوننت Image (پیشوند /uploads/) ✅
- مشکل: تصاویر آپلودشده (بلاگ، صفحات سایت، سکشنها) در بکآفیس نمایش داده نمیشدند — مسیر
GwUrl + Srcبا مسیرUploadsControllerهماهنگ نبود - رفع: اضافه شدن
/uploads/بینFileBaseUrlو مسیر نسبی تصویر - فایل:
BackOffice/Common/BaseComponents/Image.razor.cs
۱۳.۲ — فیکس فیلتر هفته در گزارشهای هفتگی ✅
- مشکل: فیلتر هفته از
MudTextField(ورودی متنی) استفاده میکرد — کاربر باید عدد حدس میزد - رفع: جایگزینی با
WeekNumberPicker— انتخاب هفته از لیست با بایندینگWeekDefinitionId - فایلها:
CMS/src/CMSMicroservice.Protobuf/Protos/commission.proto— تغییر فیلدها ازStringValueبهInt64ValueCMS/.../CommissionCQ/Queries/GetAllWeeklyPools/GetAllWeeklyPoolsQuery.cs+Handler.csBackOffice/Pages/Commission/WeeklyReports.razor
۱۳.۳ — فیکس دانلود PDF قراردادها ✅
- مشکل: فیلد
SignedPdfFileمحتوای HTML کامل دارد (نه URL فایل PDF) — دکمه دانلود کار نمیکرد - رفع: تابع JS جدید
jsHtmlToPdf()برای باز کردن HTML در پنجره جدید و چاپ/ذخیره بهعنوان PDF - فایلها:
BackOffice/wwwroot/js/main.js— تابعjsHtmlToPdfBackOffice/Pages/Contract/UserContractPage.razorBackOffice/Pages/Contract/ContractDetailsDialog.razor
۱۳.۴ — یکسانسازی ارتفاع ویرایشگر HTML ✅
- مشکل: ارتفاع
MudHtmlEditorدر صفحات مختلف متفاوت بود — برخی خیلی کوتاه - رفع: اضافه شدن
MinHeight="300px"به تمام ۷ ویرایشگر HTML - فایلها:
BlogPostEditDialog,SitePageSectionEditDialog,DiscountShop/ProductFormDialog,Package/CreateDialog,Package/UpdateDialog,Products/CreateDialog,Products/UpdateDialog
۱۳.۵ — تولید خودکار اسلاگ بلاگ ✅
- مشکل: کاربر باید اسلاگ URL را دستی وارد میکرد — غیرضروری و مستعد خطا
- رفع: حذف فیلد اسلاگ از فرم، تولید خودکار
post-{GUID}در بکاند (حداکثر ۲۰ کاراکتر) - فایلها:
CMS/.../BlogPostCQ/Commands/CreateBlogPost/CreateBlogPostCommandHandler.csCMS/.../BlogPostCQ/Commands/UpdateBlogPost/UpdateBlogPostCommandHandler.csBackOffice/Pages/Blog/Components/BlogPostEditDialog.razor
۱۳.۶ — انتقال تگها به منوی جداگانه ✅
- مشکل: تگها فقط از تب سوم بلاگ قابل دسترسی بودند — ولی تگها بین محصولات و بلاگ مشترکند
- رفع: اضافه شدن مسیر
/tagsبهTagManagementPage، لینک جدید «مدیریت تگها» در منوی ناوبری، حذف تب تگها ازBlogHub - فایلها:
BackOffice/Pages/Tag/TagManagementPage.razorBackOffice/Shared/NavMenu.razorBackOffice/Pages/Blog/BlogHub.razor
۱۳.۷ — تولید خودکار کلید سکشن ✅
- مشکل: کاربر باید کلید سکشن صفحه سایت را دستی وارد میکرد (مثلاً
about-us-section) - رفع: فیلد اختیاری شد، تولید خودکار
section-{GUID}(حداکثر ۲۰ کاراکتر) در هندلر CMS - فایلها:
CMS/.../SitePageCQ/Commands/CreateSitePageSection/CreateSitePageSectionCommandHandler.csCMS/.../SitePageCQ/Commands/CreateSitePageSection/CreateSitePageSectionCommandValidator.csBackOffice/Pages/Content/Components/SitePageSectionEditDialog.razor
🏷 فاز ۱۲ — فیکس فلوی ثبتنام / ورود FrontOffice (بهمن ۱۴۰۴)
هدف: رفع ۳ باگ بحرانی در فلوی ثبتنام و ورود FrontOffice مستند کامل:
totalDoc/cms/REGISTRATION-FLOW-FIXES.md
۱۲.۱ — رفع ایجاد کاربر جدید در VerifyOtpToken 🔴 ✅
- مشکل:
UserCQ/VerifyOtpTokenCommandHandlerکاربران جدید ایجاد نمیکرد — فقط خطای «کاربر یافت نشد» - رفع: اضافه شدن لاجیک کامل: اعتبارسنجی کد معرف، بررسی ظرفیت درخت باینری (حداکثر ۲ فرزند)، تعیین شاخه (چپ/راست)، ایجاد User + UserRole + UserWallet، رویدادهای دامنه
- فایل:
CMS/src/CMSMicroservice.Application/UserCQ/Commands/VerifyOtpToken/VerifyOtpTokenCommandHandler.cs
۱۲.۲ — رفع جستجوی موبایل در AcceptContract 🔴 ✅
- مشکل:
_currentUserService.Username="{FirstName} {LastName}"— نه شماره موبایل! در نتیجه OTP و کاربر هیچوقت پیدا نمیشد - رفع: ابتدا کاربر از
UserIdپیدا شود، سپسuser.Mobileبرای جستجوی OTP استفاده شود - فایل:
CMS/src/CMSMicroservice.Application/UserCQ/Commands/AcceptContract/AcceptContractCommandHandler.cs
۱۲.۳ — رفع IsCompleteRegister() در FrontOffice 🟡 ✅
- مشکل:
InitUserAuthInfo().GetAwaiter()بدون.GetResult()— عملیات async اجرا نمیشود، منوی کناری وضعیت نادرست - رفع: تغییر به
InitUserAuthInfo().GetAwaiter().GetResult() - فایل:
FrontOffice/src/FrontOffice.Main/Utilities/AuthService.cs
🏷 فاز ۱۱ — رفع خطای صفحات + سرویس عمومی تصاویر (بهمن ۱۴۰۴)
هدف: رفع خطای ۳ صفحه BackOffice + ایجاد اندپوینت HTTP عمومی برای سرو تصاویر
۱۱.۱ — سرویس عمومی سرو تصاویر (CMS) ✅
UploadsController— اندپوینتGET /uploads/{path}برای سرو مستقیم فایلها[AllowAnonymous]— بدون نیاز به احراز هویت- کش مرورگر ۲۴ ساعته (
ResponseCache) - پشتیبانی از Range Requests
- FMS Fallback: اگر فایل محلی نباشد، از
dl.afrino.coدانلود و کش میشود IHttpClientFactoryبا named client"FMS"(timeout: 30s)- فایلها:
CMS/WebApi/Controllers/UploadsController.cs,CMS/WebApi/Program.cs
۱۱.۲ — رفع صفحه «صفحات سایت» ✅
- اضافه شدن دکمه «افزودن صفحه جدید» به بالای صفحه
- اضافه شدن دکمه «حذف» (آیکون قرمز) برای هر ردیف
- ایجاد
SitePageCreateDialog— دیالوگ ایجاد صفحه جدید با فیلدها:- کلید صفحه (PageKey)، عنوان، توضیحات متا، عنوان هیرو، زیرعنوان هیرو، تصویر هیرو، وضعیت
- Proto: اضافه شدن
CreateSitePageوDeleteSitePageRPC - CQRS:
CreateSitePageCommand/HandlerوDeleteSitePageCommand/Handler - فایلها:
sitepage.proto— 2 RPC جدید + پیامهای Request/ResponseSitePageCQ/Commands/CreateSitePage/— Command + HandlerSitePageCQ/Commands/DeleteSitePage/— Command + HandlerCMS/WebApi/Services/SitePageService.cs— 2 override جدیدBackOffice/Services/Content/ISitePageService.cs—CreateAsync+DeleteAsync+SitePageCreateDtoBackOffice/Services/Content/SitePageService.cs— پیادهسازی Create/DeleteBackOffice/Pages/Content/SitePageManagementPage.razor— دکمههای Add/DeleteBackOffice/Pages/Content/SitePageManagementPage.razor.cs— متدهای CreatePage/DeletePageBackOffice/Pages/Content/Components/SitePageCreateDialog.razor+.razor.cs
۱۱.۳ — رفع صفحه «قراردادها» (Contracts) ✅
- مشکل: صفحه
/contractsاصلاً بارگذاری نمیشد — crash در DI - علت:
UserContractContract.UserContractContractClientدر DI ثبت نشده بود - رفع: اضافه شدن
using CMSMicroservice.Protobuf.Protos.UserContractو ثبت gRPC client - فایل:
BackOffice/Common/Configure/ConfigureService.cs
۱۱.۴ — رفع صفحه «کیف پول کاربران» (Wallets) ✅
- مشکل: صفحه
/walletsاصلاً بارگذاری نمیشد — crash در DI - علت: دو سرویس ثبت نشده بود:
UserWalletContract.UserWalletContractClientUserWalletChangeLogContract.UserWalletChangeLogContractClient
- رفع: اضافه شدن usingها و ثبت هر دو gRPC client
- فایل:
BackOffice/Common/Configure/ConfigureService.cs
🏷 فاز ۱۰ — بهبود مدیریت محتوا: بلاگ + صفحات سایت (بهمن ۱۴۰۴)
هدف: فعالسازی آپلود تصویر باینری و ادیتور HTML در صفحات بلاگ و صفحات سایت
۱۰.۱ — بهبود ادیتور پست بلاگ ✅
MudTextField Lines="10"→MudHtmlEditorبرای ویرایش محتوای HTML- فیلد متنی مسیر تصویر →
MudFileUploadبا پیشنمایش تصویر (Imagecomponent) - حذف فیلد
FeaturedImageThumbnailPath(تولید خودکار توسط بکاند) - اضافه شدن
MudFormبا اعتبارسنجی + حالت بارگذاری (_loading) - مدیریت خطا: try-catch + Snackbar
- فایلها:
Pages/Blog/Components/BlogPostEditDialog.razor+.razor.cs
۱۰.۲ — بهبود ادیتور صفحه سایت ✅
- فیلد متنی Hero Image →
MudFileUploadبا پیشنمایش تصویر - اضافه شدن
MudForm+ حالت آپلود + مدیریت خطا - فایلها:
Pages/Content/Components/SitePageEditDialog.razor+.razor.cs
۱۰.۳ — بهبود ادیتور بخش صفحه سایت (Section) ✅
MudTextField Lines="8"→MudHtmlEditorبرای ویرایش محتوای HTML بخشها- فیلدهای متنی تصویر/thumbnail →
MudFileUploadبا پیشنمایش - اضافه شدن
MudForm+ حالت آپلود + مدیریت خطا - فایلها:
Pages/Content/Components/SitePageSectionEditDialog.razor+.razor.cs
۱۰.۴ — تغییرات Proto ✅
| Proto | تغییر |
|---|---|
blogpost.proto |
اضافه شدن BlogImageFileModel + فیلد image_file در Create/Update |
sitepage.proto |
اضافه شدن SitePageImageFileModel + فیلد image_file در Update/CreateSection/UpdateSection |
۱۰.۵ — تغییرات CQRS (بکاند CMS) ✅
- Commands: اضافه شدن
ImageFileBytes,ImageMime,ImageFileNameبه:CreateBlogPostCommand,UpdateBlogPostCommandUpdateSitePageCommand,CreateSitePageSectionCommand,UpdateSitePageSectionCommand
- Handlers: تزریق
IFileManager+ فراخوانیUploadImageAsync:- BlogPost →
Images/BlogPosts/ - SitePage →
Images/SitePages/ - SitePageSection →
Images/SitePageSections/
- BlogPost →
۱۰.۶ — تغییرات سرویسهای BackOffice ✅
BlogPostService.cs— ارسالBlogImageFileModelباByteString.CopyFrom(dto.ImageFile)SitePageService.cs— ارسالSitePageImageFileModelدر Update/CreateSection/UpdateSection- DTOs: اضافه شدن
ImageFile,ImageMime,ImageFileNameبهBlogPostEditDto,SitePageEditDto,SitePageSectionEditDto
خلاصه آمار فاز ۱۰
| معیار | تعداد |
|---|---|
| فایلهای proto تغییریافته | 2 |
| Commandهای بروزشده | 5 |
| Handlerهای بروزشده | 5 |
| سرویسهای gRPC تغییریافته | 2 (BlogPostService + SitePageService) |
| دیالوگهای UI بازنویسیشده | 3 (BlogPost, SitePage, SitePageSection) |
| سرویسهای BackOffice بروزشده | 2 |
| DTOهای بروزشده | 3 |
| Build | 0 Error ✅ (هر ۳ پروژه) |
🏷 فاز ۹ — معماری مدیریت فایل + رفع سفارشات + مهاجرت DB (بهمن ۱۴۰۴)
مستند کامل معماری فایل:
totalDoc/cms/FILE-MANAGEMENT-ARCHITECTURE.md
۹.۱ — حذف کد مرده FMS ✅
- حذف ۳ فایل غیرقابل استفاده مرتبط با FMS خارجی (
https://dl.afrino.co):
| فایل حذفشده | شرح |
|---|---|
Infrastructure/Services/FmsFileManager.cs |
پیادهسازی HTTP upload به FMS |
Application/Common/FileManager/FileManagementService.cs |
سرویس قدیمی مدیریت فایل |
Application/Common/FileManager/IFileManagementService.cs |
اینترفیس قدیمی |
۹.۲ — رفع صفحه سفارشات (Orders) ✅
مشکل ۱ — صفحه خالی (بدون پیغام خطا)
- علت:
ServerReloadبدون try-catch — exceptionهای gRPC ساکت میشدند - رفع: اضافه شدن try-catch + نمایش خطا با Snackbar
- فایل:
Pages/UserOrder/UserOrderMainPage.razor.cs
مشکل ۲ — Shadow FK تکراری در OrderVAT
- علت:
.WithOne()بدون inverse navigation → EF Core یک shadow FK اضافی میساخت - رفع:
.WithOne()→.WithOne(x => x.OrderVAT) - فایل:
Persistence/Configurations/OrderVATConfiguration.cs
مشکل ۳ — فیلترهای oneof همیشه فعال
- علت: فیلدهای proto
oneofمقدار پیشفرض enum دارند (هیچوقت null نیستند)، پسPaymentStatus != nullهمیشه true بود - رفع:
PaymentStatus != null→HasPaymentStatus == true(و مشابه برای DeliveryStatus و PaymentMethod) - فایلها:
UserOrderService.cs— هر دو متدGetAllUserOrderByFilterوGetCustomerOrders
۹.۳ — مهاجرت DB: حذف محدودیت طول ستونهای تصویر ✅
- علت: data URIهای base64 بزرگتر از
nvarchar(500)بودند → truncation خاموش - رفع: حذف
HasMaxLength(500)از تمام ستونهای image path - Migration:
RemoveImagePathMaxLength
| Entity | ستونها |
|---|---|
| Product | ImagePath, ImageThumbnailPath |
| DiscountProduct | ImagePath, ImageThumbnailPath |
| Category | ImagePath |
| DiscountCategory | ImagePath |
| BlogPost | FeaturedImagePath, FeaturedImageThumbnailPath |
| SitePage | HeroImagePath |
| SitePageSection | ImagePath, ImageThumbnailPath |
۹.۴ — بازنویسی کامل مدیریت فایل: ذخیره دیسکی ✅
معماری قبلی: ذخیره data URI مستقیم در DB (ناکارآمد + حجم بالا)
معماری جدید:
- فایلها در دیسک ذخیره میشوند:
Uploads/Images/{folder}/{guid}.jpg - مسیر نسبی در DB ذخیره میشود
ImagePathResolverInterceptorهنگام serve تبدیل به base64 میکند
فایلهای اصلی:
| فایل | شرح |
|---|---|
Application/Common/FileManager/IFileManager.cs |
اینترفیس: Upload, UploadImage, Delete, ResolveImageUrl |
Infrastructure/Services/LocalFileManager.cs |
پیادهسازی: ImageSharp, main 1200×1200 + thumb 300×300, JPEG Q75 |
WebApi/Interceptors/ImagePathResolverInterceptor.cs |
gRPC Interceptor: walk بازگشتی response → تبدیل path به data URI |
تنظیمات:
FileStorage:UploadPath→ پوشه ریشه آپلود (پیشفرض:AppContext.BaseDirectory/Uploads)- gRPC MaxReceiveMessageSize: 50MB
۹.۵ — پاکسازی LoggingBehaviour ✅
- قبل: فیلدهای باینری (byte[] تصاویر) کامل در لاگ چاپ میشدند → لاگهای چند مگابایتی
- بعد:
- فرمت:
JsonFormatter.Default.Format()به جای{@Request} - Regex: حذف فیلدهای باینری (
File,ImageFile,image_file,file) - محدودیت: حداکثر 2000 کاراکتر
- فرمت:
- فایل:
WebApi/Common/Behaviours/LoggingBehaviour.cs
خلاصه آمار فاز ۹
| معیار | تعداد |
|---|---|
| فایلهای حذفشده (کد مرده) | 3 |
| فایلهای جدید | 2 (LocalFileManager بازنویسی + ImagePathResolverInterceptor) |
| فایلهای ویرایششده | ~12 |
| باگهای رفعشده | 4 (Orders page ×3 + DB truncation) |
| Migrationهای جدید | 1 (RemoveImagePathMaxLength) |
| ستونهای DB تغییریافته | 9 (nvarchar(500) → nvarchar(max)) |
| Build | 0 Error ✅ (هر ۳ پروژه) |
🏷 فاز ۸ — یکسانسازی فروشگاه عادی و تخفیفی (بهمن ۱۴۰۴)
مستند کامل:
totalDoc/ui-modernization/BACKOFFICE-STORE-UNIFICATION.md
۸.۱ — بازسازی NavMenu ✅
- ایجاد دو NavGroup مجزا: «فروشگاه عادی» و «فروشگاه تخفیفی»
- حذف «ویرایش دستهجمعی» از منو
- انبارداری → گروه مستقل | پکیجها → آیتم مستقل
- فایل:
Shared/NavMenu.razor
۸.۲ — حذف گزارشهای کوچک از سفارشات ✅
- حذف کارتهای آماری (TotalOrders + TotalAmount) و نمودار Bar ارسال
- حذف فیلدها:
_stats,_statusChartLabels,_statusChartSeries - حذف متد
UpdateStats()و کلاسOrderStatsViewModel - عنوان: «سفارشهای کاربر» → «لیست سفارشات»
- فایلها:
Pages/UserOrder/UserOrderMainPage.razor+.razor.cs
۸.۳ — رفع باگ لیست خالی سفارشات ✅
- علت:
PaymentDate.ToDateTime()بدون null check → exception ساکت در WASM - رفع:
@if (context.Item.PaymentDate != null)+ fallback "-" - فایل:
Pages/UserOrder/UserOrderMainPage.razor
۸.۴ — بازنویسی صفحه محصولات تخفیفی ✅
- تبدیل به
BasePageComponent(مطابق فروشگاه عادی) - فیلترهای جدید: وضعیت + موجودی
- ستونهای جدید: تصویر inline + عنوان truncate + چیپ رنگی موجودی + چیپ وضعیت
- فایلها:
Pages/DiscountShop/DiscountProductsMainPage.razor+.razor.cs(بازنویسی کامل)
۸.۵ — بازنویسی صفحه دستهبندیهای تخفیفی ✅
- تبدیل به
BasePageComponent(مطابق فروشگاه عادی) - ستونهای جدید: نام لاتین، دستهبندی والد (resolve شده)، تعداد محصولات، ترتیب
- code-behind جدید (
@codeدرونخطی →.razor.cs) - فایلها:
Pages/DiscountShop/DiscountCategoriesMainPage.razor+.razor.cs(بازنویسی کامل)
خلاصه آمار فاز ۸
| معیار | تعداد |
|---|---|
| فایلهای بازنویسیشده | 4 |
| فایلهای ویرایششده | 3 |
| باگهای رفعشده | 2 (PaymentDate null + لیست خالی) |
| Build | 0 Error ✅ |
🏷 فاز ۷ — پس از اجرای Audit v7.0 (تیر ۱۴۰۴)
خلاصه تغییرات
- ۵۷ مورد از ۵۸ یافته audit اجرا شد (≈98%)
- تمام ۱۶ مورد بحرانی 🔴 حل شد
- تمام ۱۸ مورد جزئی 🟢 حل شد
- فازهای ۱ تا ۶ تکمیل شدند (بهجز DayaLoan و Audit Trail که نیاز به بکاند دارند)
- فاز ۷ — Global Search, Notification Bell, NavMenu Badge, Export Excel 4 صفحه جدید
- ۱۳+ فایل جدید ساخته شد
- ۹ صفحه ادغام شدند (۱۴ صفحه → ۵ صفحه)
- Build: 0 error ✅
فاز ۷ — Global Search + Notifications + Export All + NavMenu Badge (v7.0)
6.5 — Badge Pending در NavMenu — ✅
NavMenu.razor: اضافه شدنMudBadgeروی لینک «درخواستهای برداشت»- نمایش تعداد درخواستهای Pending بصورت real-time از gRPC (
CommissionContract.GetWithdrawalRequestsAsyncباStatus=0) - fire-and-forget در
OnInitializedAsyncبا try/catch silent
6.2 — Global Search در AppBar — ✅
- فایل جدید:
Shared/GlobalSearch.razor MudAutocomplete<SearchResultItem>با Debounce 400ms- دو نوع جستجو: ۱) نام صفحات (۱۵ صفحه اصلی) ۲) کاربران از gRPC (
UserContract.GetAllUserByFilterAsync) - Template سفارشی با آیکون + عنوان + زیرنویس
- ناوبری خودکار با
Navigation.NavigateTo - اضافه شده در
MainLayout.razorداخل<AuthorizeView> - CSS در
app.css— rounded border-radius 24px, compact padding
6.1 — Notification Bell (placeholder) — ✅
MainLayout.razor: اضافه شدنMudMenu+MudBadge(Dot) + آیکون Notifications- Dropdown با هدر «اعلانها» + placeholder «اعلان جدیدی وجود ندارد»
- آماده اتصال به بکاند — فقط
Visible=trueو populate items
6.3 — Export Excel صفحات جدید — ✅ (۱۰ صفحه کامل)
- ۴ صفحه جدید اضافه شدند به ۶ صفحه قبلی:
- UserMainPage — خروجی CSV: شناسه, موبایل, نام, نام خانوادگی, کدملی
- DiscountOrdersMainPage — خروجی CSV: شماره سفارش, تاریخ, مبلغ کل, تخفیف, قابل پرداخت, تعداد, وضعیت, پرداخت
- ManualPayments — خروجی CSV: شناسه, شناسه کاربر, نام کاربر, مبلغ, نوع, وضعیت, تاریخ
- InventoryMainPage — خروجی CSV: شناسه, محصول, انبار, موجودی, رزرو, قابل فروش, حد هشدار, وضعیت
- هر ۴ صفحه: دکمه «خروجی Excel» +
ExportToExcel()+EscapeCsv()+ UTF-8 BOM +jsSaveAsFile - فایلهای code-behind جدید:
ManualPayments.razor.cs,DiscountOrdersMainPage.razor.cs
فاز ۶ — تاریخ شمسی + تاریخچهها + Export Excel (v6.0)
تاریخ شمسی یکپارچه (3.6) — ✅ کامل
- ۱۹+ فایل آپدیت شدند: تمام تاریخها از فرمت میلادی (
yyyy/MM/dd) به شمسی تبدیل شدند - از extension methodهای
DateTimeConverterCLاستفاده شد:.MiladiToJalali()— فرمت تاریخ فقط (مثال: ۱۴۰۴/۰۴/۱۲).MiladiToJalaliWithTime()— فرمت تاریخ و ساعت
- صفحات اصلاحشده شامل: Club (Members, Statistics, Features, MemberDetailsDialog)، Commission (Dashboard, WeeklyReports, WithdrawalRequests, Payouts, WithdrawalReports)، Network (UserNetworkInfo, BalancesReport, Statistics, NetworkTreeViewer)، UserOrder, Products, Package, Inventory, DiscountShop, Blog, Content, و غیره
PropertyColumn Format="yyyy/MM/dd"→TemplateColumnبا.MiladiToJalali()MudDatePicker DateFormatتغییر نکرد (قابلیت تقویم شمسی نیاز به کتابخانه جداگانه دارد)
تاریخچه عضویت باشگاه (5.7) — ✅
MemberDetailsDialog.razor: تب تاریخچه با فیلدهای صحیح proto:- ستونها:
Action,Created,PackageName,Reason,PerformedBy - Request:
PageIndex = 0(نه PageNumber)
- ستونها:
تاریخچه تغییرات شبکه (5.8) — ✅
UserNetworkInfo.razor: تب تاریخچه با فیلدهای تخصصی:- ستونها:
Action,Created,OldParentId → NewParentId,OldNetworkLeg → NewNetworkLeg(چپ/راست) - ستون
ReasonوPerformedByاضافه شد - Request:
PageIndex = 0
- ستونها:
لاگ اجرای Workerها (5.6) — ✅
- در تب WorkerControl از SystemHub قبلاً پیادهسازی شده بود
Export Excel / CSV (6.3) — ✅ ۶ صفحه
قابلیت خروجی CSV (سازگار با Excel) به ۶ صفحه اصلی اضافه شد:
| صفحه | فایل(ها) | ستونهای خروجی |
|---|---|---|
| Products (قبلاً موجود) | ProductsMainPage.razor.cs | — |
| Club Members | ClubMembers.razor + .razor.cs | شناسه,کاربر,نام,پکیج,کد فعالسازی,تاریخ فعالسازی,تاریخ انقضا,فعال,منقضی |
| Withdrawal Requests | WithdrawalRequests.razor + .razor.cs | شناسه,کاربر,نام,مبلغ,وضعیت,روش,شبا,تاریخ درخواست,تاریخ پردازش,مرجع بانکی |
| Weekly Reports | WeeklyReports.razor + .razor.cs | هفته,مبلغ استخر,موجودیها,ارزش,وضعیت,تاریخ محاسبه |
| User Orders | UserOrderMainPage.razor + .razor.cs | شناسه,کاربر,نام,مبلغ,وضعیت پرداخت,وضعیت ارسال,روش پرداخت,تاریخ |
| Stock Movements | MovementsPage.razor + .razor.cs | شناسه,محصول,نوع,تعداد,قبل,بعد,مرجع,یادداشت,تاریخ |
الگوی پیادهسازی:
- دکمه
<MudButton>با آیکونFileDownloadدر ToolBarContent StringBuilder→ CSV با هدرهای فارسی- UTF-8 BOM (
Encoding.UTF8.GetPreamble()) برای نمایش صحیح فارسی در Excel jsSaveAsFile(filename, base64)ازwwwroot/js/main.js- متد
EscapeCsv()برای مقادیر حاوی کاما/کوتیشن - تاریخها در خروجی نیز شمسی هستند
فایلهای جدید (این نسخه)
| فایل | عملکرد |
|---|---|
Pages/Commission/WeeklyReports.razor.cs |
Code-behind برای export (بهدلیل محدودیت Razor parser با escaped quotes) |
نسخه قبلی — Audit v5.0 (خرداد ۱۴۰۴)
تم رنگی یکپارچه
CustomMudTheme.cs: تم Primary از#0380C0به#6366f1(Indigo) تغییر کرد — هماهنگ با FrontOfficePaletteDarkاضافه شد: Surface#1a1a2e, Background#16213e, AppbarBackground#0f3460app.css: رنگ loading از#1b6ec2بهvar(--mud-palette-primary)تغییر کردNavMenu.razor.css: رنگ active از#0380C0هاردکد به CSS variable تغییر کردMainLayout.razor: حذف inline styleborder: 1px solid #5e4df9
Dark Mode Toggle
- آیکون ماه/آفتاب در AppBar اضافه شد
_isDarkModestate باMudThemeProviderاتصال دارد- تعویض بین
PaletteLightوPaletteDarkدر CustomMudTheme
عنوان اپلیکیشن
- "پنل مدیریت فرصت" → "پنل مدیریت کارا بازار سلامت"
فاز ۲ — بازطراحی لایوت صفحات
BasePageComponent بازنویسی کامل
- قبل: فیلتر ثابت سمت راست (20%) + جدول (80%)، ارتفاع 85vh هاردکد
- بعد: فیلتر collapsible بالای جدول، فیلدها در
MudGridباMudItem، responsive - ۱۳ صفحه آپدیت شدند: User, Products, Package, Category, UserOrder, UserAddress, UserRole, Role, BlogPost, BlogCategory, Tag, Transactions, Content
DataGrid Height یکسانسازی
- همه DataGridها:
Height="calc(100vh - 240px)" - صفحات اصلاحشده: تمام ~33 صفحه دارای DataGrid
Pager یکسانسازی
- PageSize: همه
20, 50, 100 - متن فارسی:
RowsPerPageString="تعداد در صفحه"وInfoFormat="سطر {first_item} تا {last_item} از {all_items}"
MaxWidth یکسانسازی
MainLayout.razorMudContainer wrapper اضافه شد → MaxWidth یکسان برای همه صفحات- ۳۱ صفحه: حذف
MudContainerتکراری (double nesting)
Breadcrumb
Shared/AppBreadcrumb.razorساخته شد- جداکننده چپبهراست (
ChevronLeft) - نقشه فارسی URL segments (60+ مسیر)
- آخرین آیتم disabled (صفحه فعلی)
Login + VerifyCode بازطراحی
- عرض ثابت 35% → responsive
MaxWidth.Small - لوگو + برندینگ "کارا بازار سلامت" اضافه شد
- طراحی gradient background
فاز ۲.۵ — پاکسازی ساختاری
NavMenu بازسازی کامل
- لینک مرده
categories-dragdrop: حذف شد - Transactions: حذف از NavMenu (صفحه stub خالی)
- AlertsMonitoring: حذف از NavMenu (100% mock)
- WorkerControl: به SystemHub منتقل شد (قبلاً لینک نداشت)
- «پیامهای عمومی»: از بخش فروشگاه تخفیفی به «مدیریت محتوا» منتقل شد
- ساختار گروهبندی اصلاح شد:
- کمیسیون و شبکه: NavGroup واضح
- باشگاه مشتریان: اعضا و آمار + فیچرها
- فروشگاه: پکیجها، محصولات (group)، سفارشها، فروشگاه تخفیفی (group)
- مدیریت: کاربران، نقشها، پرداخت دستی، کیفپول (جدید)، قراردادها (جدید)
- محتوا: بلاگ، صفحات سایت، پیامهای عمومی
- سیستم: مدیریت سیستم، نسخه اپها
فاز ۳ — UX بهبودها
NoRecordsContent (Empty State)
- ۳۳ DataGrid آپدیت شدند
- پیام:
<MudAlert Severity="Info">موردی یافت نشد.</MudAlert>
Delete Confirmation با نام آیتم
- ۱۱ صفحه اصلاح شدند:
- Role →
«{model.Title}» - User →
«{model.FirstName} {model.LastName}» - Package →
«{model.Title}» - UserAddress →
«{model.Title}» - UserRole →
شناسه «{model.Id}» - UserOrder →
شماره «{model.Id}» - Category →
«{model.Title}» - Products →
«{model.Title}» - DiscountCategories →
«{category?.Title}»(lookup اضافه شد) - DiscountProducts →
«{product?.Title}»(lookup اضافه شد) - PublicMessages →
«{message?.Title}»(lookup اضافه شد)
- Role →
User Menu در AppBar
MudMenuجایگزین متن ساده شماره موبایل شد- آیتمها: نام کاربر (غیرفعال) + خروج
- آیکون
AccountCircle - خروج (
signout) از NavMenu به AppBar منتقل شد
فاز ۳.۵ — ادغام صفحات
Dashboard Merge ← Pages/Index.razor
Index.razor+SystemOverview.razorادغام شدند- Routes:
/+/dashboard/overview - بخشها:
- 6 کارت آمار CMS (کاربران، محصولات، پکیجها، دستهبندیها، سفارشها، مبلغ پرداختشده)
- آمار کمیسیون (هفته جاری، استخر، موجودیها، وضعیت محاسبه)
- آمار باشگاه (کل/فعال/غیرفعال)
- جدول آخرین ۵ سفارش پرداختشده
- ۶ دکمه Quick Action
- بارگذاری موازی با
Task.WhenAll+.ResponseAsync SystemOverview.razorحذف شد
DiscountShopHub ← Pages/DiscountShop/DiscountShopHub.razor
- Routes:
/discount-shop,/discount-orders,/discount-sales-reports - ۲ تب: DiscountOrdersMainPage + SalesReports
- انتخاب تب از URL
ClubHub ← Pages/Club/ClubHub.razor
- Routes:
/club,/club/members,/club/statistics - ۲ تب: ClubMembers + Statistics
BlogHub ← Pages/Blog/BlogHub.razor
- Routes:
/blog,/blog/posts,/blog/categories,/tags - ۳ تب: BlogPostManagementPage + BlogCategoryManagementPage + TagManagementPage
SystemHub ← Pages/SystemManagement/SystemHub.razor
- Routes:
/system,/system/configuration,/system/worker-control,/system/health - ۳ تب: Configuration + WorkerControl + HealthDashboard
۱۰ صفحه — @page directive حذف شد
صفحاتی که به hub منتقل شدند دیگر route مستقل ندارند: DiscountOrdersMainPage, SalesReports, ClubMembers, Statistics, BlogPostManagementPage, BlogCategoryManagementPage, TagManagementPage, Configuration, WorkerControl, HealthDashboard
فاز ۴ — فیکسهای بیزینسی
Dashboard آمار اصلاح شد
- قبل: آمار از ۱۰ رکورد اول محاسبه میشد (نادرست)
- بعد: از
metadata.TotalCountو APIهای جداگانه استفاده میشود
ManualPayments — تأیید/رد
- دکمههای Approve/Reject وقتی
Status==0(در انتظار) نمایش داده میشوند - Confirmation dialog قبل از اجرا
- از
ManualPaymentId(نهId) استفاده میشود
UserOrder — فیلتر Cancelled
<MudSelectItem Value="@(5)">لغو شده</MudSelectItem>اضافه شد
WithdrawalRequests — بهبود کامل
- Pager: 10/25/50/100 → 20/50/100
WithdrawalDetailsDialog.razor(جدید): نمایش کامل اطلاعات کاربر، درخواست، و بانکیRejectReasonDialog.razor(جدید): ورود دلیل رد با اعتبارسنجی- ViewDetails: از Snackbar TODO به دیالوگ واقعی تغییر کرد
- RejectRequest: از دلیل هاردکد به دیالوگ custom تغییر کرد
فاز ۵ — صفحات مفقود (CMS-Derived)
WalletManagementPage ← Pages/Wallet/WalletManagementPage.razor
- Route:
/wallets - تب ۱ — کیفپولها: DataGrid با ServerData، فیلتر UserAutoComplete
- ستونها: شناسه، کاربر، موجودی اصلی، موجودی شبکه، مشاهده تغییرات
- نوع:
GetAllUserWalletByFilterResponseModel
- تب ۲ — تاریخچه تغییرات: DataGrid با ServerData، فیلتر کاربر + نوع (افزایش/کاهش)
- ستونها: شناسه، کیفپول، نوع (چیپ رنگی)، تغییر موجودی، موجودی فعلی، تغییر شبکه، موجودی شبکه فعلی، شناسه مرجع، تاریخ
- نوع:
GetAllUserWalletChangeLogByFilterResponseModel - فیلدهای proto با typo:
ChangeNerworkValue,RefrenceId
UserContractPage ← Pages/Contract/UserContractPage.razor
- Route:
/contracts - DataGrid با ServerData، فیلتر UserAutoComplete
- ستونها: شناسه، کاربر، قرارداد، کد امضا، لینک PDF، جزئیات
- نوع:
GetAllUserContractByFilterResponseModel
ContractDetailsDialog ← Pages/Contract/ContractDetailsDialog.razor
- جدول ساده: شناسه، کاربر، قالب قرارداد، کد امضا، لینک دانلود PDF
ClubFeaturesPage ← Pages/Club/ClubFeaturesPage.razor
- Route:
/club/features - تب ۱ — فیچرهای تعریفشده: کارتهای MudPaper با عنوان، توضیحات، وضعیت (فعال/غیرفعال)، ترتیب
- از
ConfigClient.GetClubFeaturesAsync
- از
- تب ۲ — فیچرهای کاربران: DataGrid با فیلتر کاربر، سوئیچ فعال/غیرفعال
- از
ClubClient.GetUserClubFeaturesAsync+ToggleUserClubFeatureAsync
- از
⚠️ نکات فنی مهم
الگوهای Proto
- فیلتر:
new GetAllXxxByFilterFilter()(سطح بالا، بدون.Types.) - پاسخ لیست:
GetAllXxxByFilterResponseModel(نهGetXxxResponse) - Typoها در proto:
ChangeNerworkValueوRefrenceId— باید دقیقاً همینها استفاده شوند
_Imports.razor — سرویسهای Global
سرویسهای زیر از _Imports.razor تزریق میشوند و نباید در code-behind با [Inject] دوباره تعریف شوند:
NavigationManager NavigationILocalStorageService LocalStorageServiceISnackbar SnackbarIJSRuntime jsRuntimeIDialogService DialogServiceAuthenticationStateProvider
MudBlazor محدودیتها
Variant.Flatوجود ندارد → ازVariant.Textاستفاده شودGutterSizeرویMudGriddeprecated است
فاز ۴ (ادامه) — تکمیل فیکسهای بیزینسی
UserSettings — حذف تبهای جعلی (2.5.5)
UserSettings.razor: تب Notifications (۷ تاگل جعلی بدون بکاند) → placeholder «بهزودی فعال میشود» با آیکون NotificationsActiveUserSettings.razor: تب Security (فرم تغییر رمز + 2FA بدون بکاند) → placeholder «بهزودی فعال میشود» با آیکون Lock- حذف کد مرده: ~۱۵ متغیر notification/security + متدهای
SaveNotificationSettings(),SaveSecuritySettings(),ChangePassword()
HealthDashboard — حذف متریکهای Mock (2.5.6)
HealthDashboard.razor: بخش System Resources (۴ کارت CPU=45.2%, Memory=62.8%, Disk=73.5%, Network) → یک کارت با پیام «مانیتورینگ منابع سیستم در نسخههای آینده با اتصال به Prometheus/Grafana فعال خواهد شد»- حذف کد مرده: ۹ متغیر mock (
_cpuUsage,_memoryUsage, etc.) + متدGetResourceColor()
حذف cursor:pointer زائد (4.10)
Style="cursor:pointer;"از ۱۷ فایل حذف شد (MudButton/MudIconButton خودشان cursor:pointer دارند)- شامل: ProductsMainPage, GalleryDialog, Image.razor (base component), RoleMainPage, UserOrderMainPage, PackageMainPage, etc.
حذف Console.WriteLine (4.11)
- از ۱۱ فایل حذف شد: DiscountProductService, DiscountCategoryService, NetworkTreeViewer, UserSettings, CategoryMainPage, UserOrderMainPage, Commission/Dashboard, DiscountProductsMainPage, DiscountCategoryMultiSelectCombo, UserRole/CreateDialog
Commission/Dashboard.razor.cs:using System.Text.Jsonهم حذف شد (دیگر استفاده نمیشد)
DiscountProducts — فیلتر دستهبندی (4.7)
DiscountProductsMainPage.razor:@inject IDiscountCategoryServiceاضافه شد- دستهبندیهای فعال از سرویس بارگذاری و در MudSelect نمایش داده میشوند
- جایگزینی
@* TODO: Load categories *@با@foreachواقعی
DiscountProducts — Items → ServerData (4.8)
DiscountProductsMainPage.razor: تبدیل ازItems="@_products"بهServerData="LoadServerData"- متد
LoadServerData(GridState<T>)اضافه شد باPageNumberوPageSizeاز state Height="calc(100vh - 300px)"+FixedHeader="true"اضافه شد- Snackbar اطلاعرسانی اضافی در هر بارگذاری حذف شد (redundant)
UserOrder — فعالسازی آمار (4.6)
UserOrderMainPage.razor: بخش آمار (MudCard + MudChart) از حالت comment خارج شد- نمایش تعداد سفارشها + مجموع مبلغ + نمودار Bar وضعیت ارسال
UserSettings — persist با localStorage (4.9)
- تب General از قبل با localStorage کار میکرد ✅ (فقط تبهای جعلی حذف شدند)
فاز ۴.۵ — Cross-Navigation
لینک نام کاربر → پروفایل (4.5.1, 4.5.2)
UserOrderMainPage.razor: ستونUserFullNameاز PropertyColumn به TemplateColumn تبدیل شد — MudLink به/network/user-info/{UserId}UserPayouts.razor: نام/شناسه کاربر به MudLink تبدیل شد →/network/user-info/{UserId}WithdrawalRequests.razor: نام کاربر به MudLink تبدیل شد →/network/user-info/{UserId}
لینک محصول ↔ انبار (4.5.3, 4.5.4) — Skip
- صفحه جزئیات محصول وجود ندارد (فقط لیست + دیالوگ ویرایش)
- لینک cross-navigation بدون صفحه مقصد معنادار نیست
Extract shared status helpers (3.5.6) — Skip
- بررسی نشان داد هر context مقادیر متفاوتی دارد:
- UserPayouts: status 1 = Success/پرداخت شده
- WithdrawalRequests: status 1 = Info/واریز شده
- PayoutDetailsDialog: فقط ۳ وضعیت (نه ۶)
- استخراج به helper مشترک باعث از دست رفتن معنای domain-specific میشود
📈 آمار تغییرات
| معیار | تعداد |
|---|---|
| فایلهای جدید | 11 |
| فایلهای حذفشده | 1 (SystemOverview.razor) |
| فایلهای ویرایششده | ~65+ |
| DataGridهای آپدیتشده | 33 |
| Delete confirmation اصلاحشده | 11 |
| صفحات ادغامشده | 14 → 5 |
| خطاهای build حلشده | 9+ |
| Console.WriteLine حذفشده | 22+ (از ۱۱ فایل) |
| cursor:pointer حذفشده | 17 فایل |
| Cross-link اضافهشده | 3 صفحه (UserOrder, UserPayouts, WithdrawalRequests) |