Merge branch 'kub-stage' into production
Build and Deploy to Production / build-and-deploy (push) Successful in 7m46s
Build and Deploy to Production / build-and-deploy (push) Successful in 7m46s
This commit is contained in:
+2
-1009
File diff suppressed because it is too large
Load Diff
@@ -1,792 +1,3 @@
|
||||
# 📝 BackOffice — Changelog
|
||||
# Docs moved to totalDoc
|
||||
|
||||
**آخرین بروزرسانی:** اسفند ۱۴۰۴ (February 17, 2026)
|
||||
|
||||
---
|
||||
|
||||
## 🏷 فاز ۱۵ — Production Deploy + فیکس CI/CD Cross-Deploy (اسفند ۱۴۰۴)
|
||||
|
||||
> **هدف:** دیپلوی به سرور Production و رفع باگ cross-deploy
|
||||
|
||||
### ۱۵.۱ — Merge به برنچ production ✅
|
||||
|
||||
- **کامیت:** `4454b8d` — merge `kub-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`
|
||||
|
||||
### ۱۵.۴ — فیکس K8S_SERVER در prod-deploy.yml ✅
|
||||
|
||||
- **مشکل:** `K8S_SERVER` هنوز `194.5.195.53` (staging) بود
|
||||
- **رفع:** تغییر به `45.149.79.127` (production)
|
||||
- **فیکس اضافی:** `kubectl rollout restart` → `kubectl set image` (تا ایمیج SHA-tagged واقعاً set بشه)
|
||||
|
||||
### ۱۵.۵ — ساخت appsettings.Production.json ✅
|
||||
|
||||
- **مشکل:** فایل `appsettings.Production.json` وجود نداشت → `GwUrl` fallback به `localhost`
|
||||
- **رفع:** ساخت `wwwroot/appsettings.Production.json` با `GwUrl=https://cms.kbs1.ir`
|
||||
|
||||
### ۱۵.۶ — فیکس nginx image path در Dockerfile (production branch) ✅
|
||||
|
||||
- **مشکل:** Dockerfile روی برنچ production از `library/nginx:alpine` استفاده میکرد — وجود نداشت
|
||||
- **ارور:** `manifest for 194.5.195.53:32082/library/nginx:alpine not found`
|
||||
- **رفع:** تغییر به `194.5.195.53:32082/nginx:alpine`
|
||||
- **کامیت:** `743403e` (مستقیم روی برنچ production)
|
||||
|
||||
---
|
||||
|
||||
## 🏷 فاز ۱۴ — فیکس 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` به `Int64Value`
|
||||
- `CMS/.../CommissionCQ/Queries/GetAllWeeklyPools/GetAllWeeklyPoolsQuery.cs` + `Handler.cs`
|
||||
- `BackOffice/Pages/Commission/WeeklyReports.razor`
|
||||
|
||||
### ۱۳.۳ — فیکس دانلود PDF قراردادها ✅
|
||||
|
||||
- **مشکل:** فیلد `SignedPdfFile` محتوای HTML کامل دارد (نه URL فایل PDF) — دکمه دانلود کار نمیکرد
|
||||
- **رفع:** تابع JS جدید `jsHtmlToPdf()` برای باز کردن HTML در پنجره جدید و چاپ/ذخیره بهعنوان PDF
|
||||
- **فایلها:**
|
||||
- `BackOffice/wwwroot/js/main.js` — تابع `jsHtmlToPdf`
|
||||
- `BackOffice/Pages/Contract/UserContractPage.razor`
|
||||
- `BackOffice/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.cs`
|
||||
- `CMS/.../BlogPostCQ/Commands/UpdateBlogPost/UpdateBlogPostCommandHandler.cs`
|
||||
- `BackOffice/Pages/Blog/Components/BlogPostEditDialog.razor`
|
||||
|
||||
### ۱۳.۶ — انتقال تگها به منوی جداگانه ✅
|
||||
|
||||
- **مشکل:** تگها فقط از تب سوم بلاگ قابل دسترسی بودند — ولی تگها بین محصولات و بلاگ مشترکند
|
||||
- **رفع:** اضافه شدن مسیر `/tags` به `TagManagementPage`، لینک جدید «مدیریت تگها» در منوی ناوبری، حذف تب تگها از `BlogHub`
|
||||
- **فایلها:**
|
||||
- `BackOffice/Pages/Tag/TagManagementPage.razor`
|
||||
- `BackOffice/Shared/NavMenu.razor`
|
||||
- `BackOffice/Pages/Blog/BlogHub.razor`
|
||||
|
||||
### ۱۳.۷ — تولید خودکار کلید سکشن ✅
|
||||
|
||||
- **مشکل:** کاربر باید کلید سکشن صفحه سایت را دستی وارد میکرد (مثلاً `about-us-section`)
|
||||
- **رفع:** فیلد اختیاری شد، تولید خودکار `section-{GUID}` (حداکثر ۲۰ کاراکتر) در هندلر CMS
|
||||
- **فایلها:**
|
||||
- `CMS/.../SitePageCQ/Commands/CreateSitePageSection/CreateSitePageSectionCommandHandler.cs`
|
||||
- `CMS/.../SitePageCQ/Commands/CreateSitePageSection/CreateSitePageSectionCommandValidator.cs`
|
||||
- `BackOffice/Pages/Content/Components/SitePageSectionEditDialog.razor`
|
||||
|
||||
---
|
||||
|
||||
## 🏷 فاز ۱۲ — فیکس فلوی ثبتنام / ورود FrontOffice (بهمن ۱۴۰۴)
|
||||
|
||||
> **هدف:** رفع ۳ باگ بحرانی در فلوی ثبتنام و ورود FrontOffice
|
||||
> **مستند کامل:** [`totalDoc/cms/REGISTRATION-FLOW-FIXES.md`](../../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` و `DeleteSitePage` RPC
|
||||
- CQRS: `CreateSitePageCommand/Handler` و `DeleteSitePageCommand/Handler`
|
||||
- **فایلها:**
|
||||
- `sitepage.proto` — 2 RPC جدید + پیامهای Request/Response
|
||||
- `SitePageCQ/Commands/CreateSitePage/` — Command + Handler
|
||||
- `SitePageCQ/Commands/DeleteSitePage/` — Command + Handler
|
||||
- `CMS/WebApi/Services/SitePageService.cs` — 2 override جدید
|
||||
- `BackOffice/Services/Content/ISitePageService.cs` — `CreateAsync` + `DeleteAsync` + `SitePageCreateDto`
|
||||
- `BackOffice/Services/Content/SitePageService.cs` — پیادهسازی Create/Delete
|
||||
- `BackOffice/Pages/Content/SitePageManagementPage.razor` — دکمههای Add/Delete
|
||||
- `BackOffice/Pages/Content/SitePageManagementPage.razor.cs` — متدهای CreatePage/DeletePage
|
||||
- `BackOffice/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.UserWalletContractClient`
|
||||
- `UserWalletChangeLogContract.UserWalletChangeLogContractClient`
|
||||
- **رفع:** اضافه شدن usingها و ثبت هر دو gRPC client
|
||||
- **فایل:** `BackOffice/Common/Configure/ConfigureService.cs`
|
||||
|
||||
---
|
||||
|
||||
## 🏷 فاز ۱۰ — بهبود مدیریت محتوا: بلاگ + صفحات سایت (بهمن ۱۴۰۴)
|
||||
|
||||
> **هدف:** فعالسازی آپلود تصویر باینری و ادیتور HTML در صفحات بلاگ و صفحات سایت
|
||||
|
||||
### ۱۰.۱ — بهبود ادیتور پست بلاگ ✅
|
||||
|
||||
- **`MudTextField Lines="10"`** → **`MudHtmlEditor`** برای ویرایش محتوای HTML
|
||||
- **فیلد متنی مسیر تصویر** → **`MudFileUpload`** با پیشنمایش تصویر (`Image` component)
|
||||
- حذف فیلد `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`, `UpdateBlogPostCommand`
|
||||
- `UpdateSitePageCommand`, `CreateSitePageSectionCommand`, `UpdateSitePageSectionCommand`
|
||||
- **Handlers:** تزریق `IFileManager` + فراخوانی `UploadImageAsync`:
|
||||
- BlogPost → `Images/BlogPosts/`
|
||||
- SitePage → `Images/SitePages/`
|
||||
- SitePageSection → `Images/SitePageSections/`
|
||||
|
||||
### ۱۰.۶ — تغییرات سرویسهای 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`](../../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 (ناکارآمد + حجم بالا)
|
||||
|
||||
**معماری جدید:**
|
||||
1. فایلها در دیسک ذخیره میشوند: `Uploads/Images/{folder}/{guid}.jpg`
|
||||
2. مسیر نسبی در DB ذخیره میشود
|
||||
3. `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`](../../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 صفحات جدید — ✅ (۱۰ صفحه کامل)
|
||||
- **۴ صفحه جدید** اضافه شدند به ۶ صفحه قبلی:
|
||||
1. **UserMainPage** — خروجی CSV: شناسه, موبایل, نام, نام خانوادگی, کدملی
|
||||
2. **DiscountOrdersMainPage** — خروجی CSV: شماره سفارش, تاریخ, مبلغ کل, تخفیف, قابل پرداخت, تعداد, وضعیت, پرداخت
|
||||
3. **ManualPayments** — خروجی CSV: شناسه, شناسه کاربر, نام کاربر, مبلغ, نوع, وضعیت, تاریخ
|
||||
4. **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) تغییر کرد — هماهنگ با FrontOffice
|
||||
- **`PaletteDark`** اضافه شد: Surface `#1a1a2e`, Background `#16213e`, AppbarBackground `#0f3460`
|
||||
- **`app.css`**: رنگ loading از `#1b6ec2` به `var(--mud-palette-primary)` تغییر کرد
|
||||
- **`NavMenu.razor.css`**: رنگ active از `#0380C0` هاردکد به CSS variable تغییر کرد
|
||||
- **`MainLayout.razor`**: حذف inline style `border: 1px solid #5e4df9`
|
||||
|
||||
### Dark Mode Toggle
|
||||
- آیکون ماه/آفتاب در AppBar اضافه شد
|
||||
- `_isDarkMode` state با `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.razor` MudContainer 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 اضافه شد)
|
||||
|
||||
### 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 Navigation`
|
||||
- `ILocalStorageService LocalStorageService`
|
||||
- `ISnackbar Snackbar`
|
||||
- `IJSRuntime jsRuntime`
|
||||
- `IDialogService DialogService`
|
||||
- `AuthenticationStateProvider`
|
||||
|
||||
### MudBlazor محدودیتها
|
||||
- `Variant.Flat` وجود ندارد → از `Variant.Text` استفاده شود
|
||||
- `GutterSize` روی `MudGrid` deprecated است
|
||||
|
||||
---
|
||||
|
||||
## فاز ۴ (ادامه) — تکمیل فیکسهای بیزینسی
|
||||
|
||||
### UserSettings — حذف تبهای جعلی (2.5.5)
|
||||
- **`UserSettings.razor`**: تب Notifications (۷ تاگل جعلی بدون بکاند) → placeholder «بهزودی فعال میشود» با آیکون NotificationsActive
|
||||
- **`UserSettings.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) |
|
||||
See [totalDoc/INDEX.md](../../totalDoc/INDEX.md) for all documentation.
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
|
||||
<!-- CMS Protobuf NuGet package (used for both local dev and Docker builds) -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.180" />
|
||||
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.183" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
@using Google.Protobuf.WellKnownTypes
|
||||
@using BackOffice.Pages.Club.Components
|
||||
@using BackOffice.Pages.AutoComplete
|
||||
@using CMSMicroservice.Protobuf.Protos.ClubMembership
|
||||
|
||||
<div>
|
||||
@@ -16,7 +17,8 @@
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.h6">لیست اعضا</MudText>
|
||||
<MudSpacer />
|
||||
<MudStack Row="true" Spacing="2">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<UserAutoComplete Label="جستجوی کاربر" @bind-SelectedUserId="_filterUserId" />
|
||||
<MudSwitch T="bool" @bind-Value="_filterIsActive"
|
||||
Color="Color.Success"
|
||||
Label="فقط فعالها" />
|
||||
|
||||
@@ -16,6 +16,7 @@ public partial class ClubMembers
|
||||
|
||||
private MudDataGrid<ClubMembershipModel> _gridData;
|
||||
private bool _filterIsActive = true;
|
||||
private long? _filterUserId;
|
||||
|
||||
private async Task<GridData<ClubMembershipModel>> ServerReload(GridState<ClubMembershipModel> state)
|
||||
{
|
||||
@@ -30,6 +31,9 @@ public partial class ClubMembers
|
||||
// Always use the filter value since it's now a bool (not nullable)
|
||||
request.IsActive = _filterIsActive;
|
||||
|
||||
if (_filterUserId.HasValue && _filterUserId.Value > 0)
|
||||
request.UserId = _filterUserId.Value;
|
||||
|
||||
var result = await ClubContract.GetAllClubMembershipsAsync(request);
|
||||
|
||||
if (result?.Models != null && result.Models.Any())
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
@using CMSMicroservice.Protobuf.Protos.ClubMembership
|
||||
@using BackOffice.Pages.AutoComplete
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudForm @ref="_form" @bind-IsValid="_formValid">
|
||||
<MudStack Spacing="3">
|
||||
<MudNumericField @bind-Value="_model.UserId"
|
||||
Label="شناسه کاربر"
|
||||
Required="true"
|
||||
RequiredError="شناسه کاربر الزامی است"
|
||||
Variant="Variant.Outlined" />
|
||||
<UserAutoComplete Label="انتخاب کاربر" @bind-SelectedUserId="_model.UserId" />
|
||||
|
||||
<MudNumericField @bind-Value="_model.PackageId"
|
||||
Label="شناسه پکیج"
|
||||
@@ -67,12 +64,18 @@
|
||||
await _form.Validate();
|
||||
if (!_formValid) return;
|
||||
|
||||
if (!_model.UserId.HasValue || _model.UserId.Value <= 0)
|
||||
{
|
||||
Snackbar.Add("لطفاً کاربر را انتخاب کنید.", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
_isSubmitting = true;
|
||||
try
|
||||
{
|
||||
var request = new ActivateClubMembershipRequest
|
||||
{
|
||||
UserId = _model.UserId,
|
||||
UserId = _model.UserId.Value,
|
||||
PackageId = _model.PackageId,
|
||||
DurationMonths = _model.DurationMonths
|
||||
};
|
||||
@@ -94,7 +97,7 @@
|
||||
|
||||
private class ActivateModel
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public long? UserId { get; set; }
|
||||
public long PackageId { get; set; }
|
||||
public int DurationMonths { get; set; } = 1;
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>ارزش هر بالانس:</strong></td>
|
||||
<td>@Payout.ValuePerBalance.ToString("N0") ریال</td>
|
||||
<td>@Payout.ValuePerBalance.ToString("N0") تومان</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>مبلغ کل:</strong></td>
|
||||
<td><strong>@Payout.TotalAmount.ToString("N0") ریال</strong></td>
|
||||
<td><strong>@Payout.TotalAmount.ToString("N0") تومان</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>وضعیت:</strong></td>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<DialogContent>
|
||||
<MudStack Spacing="3">
|
||||
<MudAlert Severity="Severity.Warning" Dense="true">
|
||||
درخواست برداشت @Amount.ToString("N0") ریال برای @UserName رد خواهد شد.
|
||||
درخواست برداشت @Amount.ToString("N0") تومان برای @UserName رد خواهد شد.
|
||||
</MudAlert>
|
||||
<MudTextField @bind-Value="_reason"
|
||||
Label="دلیل رد درخواست"
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>مبلغ:</strong></td>
|
||||
<td><MudText Color="Color.Primary"><strong>@Request.Amount.ToString("N0") ریال</strong></MudText></td>
|
||||
<td><MudText Color="Color.Primary"><strong>@Request.Amount.ToString("N0") تومان</strong></MudText></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>روش برداشت:</strong></td>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<MudCard Elevation="2">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.h6" Color="Color.Primary">استخر هفتگی</MudText>
|
||||
<MudText Typo="Typo.h4">@(_poolData?.TotalPoolAmount.ToString("N0") ?? "0") ریال</MudText>
|
||||
<MudText Typo="Typo.h4">@(_poolData?.TotalPoolAmount.ToString("N0") ?? "0") تومان</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">@_currentWeekDisplayText</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
@@ -40,7 +40,7 @@
|
||||
<MudCard Elevation="2">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.h6" Color="Color.Warning">ارزش هر تعادل</MudText>
|
||||
<MudText Typo="Typo.h4">@(_poolData?.ValuePerBalance.ToString("N0") ?? "0") ریال</MudText>
|
||||
<MudText Typo="Typo.h4">@(_poolData?.ValuePerBalance.ToString("N0") ?? "0") تومان</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">قیمت واحد تعادل</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
@@ -111,7 +111,7 @@
|
||||
@if (week.TotalPoolAmount > 0)
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Color="Color.Success" Class="mr-2">
|
||||
@week.TotalPoolAmount.ToString("N0") ریال
|
||||
@week.TotalPoolAmount.ToString("N0") تومان
|
||||
</MudChip>
|
||||
}
|
||||
</MudText>
|
||||
@@ -181,7 +181,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>مجموع استخر:</strong></td>
|
||||
<td>@_poolData.TotalPoolAmount.ToString("N0") ریال</td>
|
||||
<td>@_poolData.TotalPoolAmount.ToString("N0") تومان</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>تعداد تعادل:</strong></td>
|
||||
@@ -189,7 +189,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>ارزش هر تعادل:</strong></td>
|
||||
<td>@_poolData.ValuePerBalance.ToString("N0") ریال</td>
|
||||
<td>@_poolData.ValuePerBalance.ToString("N0") تومان</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>وضعیت:</strong></td>
|
||||
|
||||
@@ -119,7 +119,7 @@ public partial class UserPayouts
|
||||
{
|
||||
var confirmed = await DialogService.ShowMessageBox(
|
||||
"تایید برداشت",
|
||||
$"آیا از تایید برداشت برای کاربر {payout.UserName} (مبلغ: {payout.TotalAmount:N0} ریال) مطمئن هستید؟",
|
||||
$"آیا از تایید برداشت برای کاربر {payout.UserName} (مبلغ: {payout.TotalAmount:N0} تومان) مطمئن هستید؟",
|
||||
yesText: "تایید", cancelText: "لغو");
|
||||
|
||||
if (confirmed == true)
|
||||
|
||||
@@ -67,13 +67,13 @@
|
||||
<PropertyColumn Property="x => x.WeekDisplayName" Title="هفته" />
|
||||
<PropertyColumn Property="x => x.TotalPoolAmount" Title="مبلغ کل استخر" Format="N0">
|
||||
<CellTemplate>
|
||||
<MudText>@context.Item.TotalPoolAmount.ToString("N0") ریال</MudText>
|
||||
<MudText>@context.Item.TotalPoolAmount.ToString("N0") تومان</MudText>
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="x => x.TotalBalances" Title="مجموع موجودیها" />
|
||||
<PropertyColumn Property="x => x.ValuePerBalance" Title="ارزش هر موجودی" Format="N0">
|
||||
<CellTemplate>
|
||||
<MudText>@context.Item.ValuePerBalance.ToString("N0") ریال</MudText>
|
||||
<MudText>@context.Item.ValuePerBalance.ToString("N0") تومان</MudText>
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="x => x.IsCalculated" Title="وضعیت">
|
||||
@@ -128,7 +128,7 @@
|
||||
<MudPaper Elevation="0" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.h6" Color="Color.Primary">مجموع استخرها</MudText>
|
||||
<MudText Typo="Typo.h4">@_totalPoolSum.ToString("N0")</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">ریال</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="3">
|
||||
@@ -149,7 +149,7 @@
|
||||
<MudPaper Elevation="0" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.h6" Color="Color.Info">میانگین ارزش</MudText>
|
||||
<MudText Typo="Typo.h4">@_averageValue.ToString("N0")</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">ریال</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
@@ -107,19 +107,19 @@
|
||||
<MudItem xs="12" md="3">
|
||||
<MudPaper Elevation="1" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Primary">مجموع مبلغ برداشتها</MudText>
|
||||
<MudText Typo="Typo.h5">@_summary.TotalAmount.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.h5">@_summary.TotalAmount.ToString("N0") تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="3">
|
||||
<MudPaper Elevation="1" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Success">مبلغ پرداخت شده</MudText>
|
||||
<MudText Typo="Typo.h5">@_summary.TotalPaid.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.h5">@_summary.TotalPaid.ToString("N0") تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="3">
|
||||
<MudPaper Elevation="1" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Warning">مبلغ در انتظار</MudText>
|
||||
<MudText Typo="Typo.h5">@_summary.TotalPending.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.h5">@_summary.TotalPending.ToString("N0") تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="3">
|
||||
@@ -189,17 +189,17 @@
|
||||
<PropertyColumn Property="x => x.PendingCount" Title="در انتظار" />
|
||||
<PropertyColumn Property="x => x.TotalAmount" Title="مبلغ کل" Format="N0">
|
||||
<CellTemplate>
|
||||
@context.Item.TotalAmount.ToString("N0") ریال
|
||||
@context.Item.TotalAmount.ToString("N0") تومان
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="x => x.PaidAmount" Title="پرداخت شده" Format="N0">
|
||||
<CellTemplate>
|
||||
@context.Item.PaidAmount.ToString("N0") ریال
|
||||
@context.Item.PaidAmount.ToString("N0") تومان
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="x => x.PendingAmount" Title="در انتظار پرداخت" Format="N0">
|
||||
<CellTemplate>
|
||||
@context.Item.PendingAmount.ToString("N0") ریال
|
||||
@context.Item.PendingAmount.ToString("N0") تومان
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
</Columns>
|
||||
@@ -431,9 +431,9 @@
|
||||
|
||||
sb.AppendLine("خلاصه:");
|
||||
sb.AppendLine($"تعداد کل درخواستها: {_summary.TotalRequests}");
|
||||
sb.AppendLine($"مبلغ کل برداشتها: {_summary.TotalAmount:N0} ریال");
|
||||
sb.AppendLine($"مبلغ پرداخت شده: {_summary.TotalPaid:N0} ریال");
|
||||
sb.AppendLine($"مبلغ در انتظار: {_summary.TotalPending:N0} ریال");
|
||||
sb.AppendLine($"مبلغ کل برداشتها: {_summary.TotalAmount:N0} تومان");
|
||||
sb.AppendLine($"مبلغ پرداخت شده: {_summary.TotalPaid:N0} تومان");
|
||||
sb.AppendLine($"مبلغ در انتظار: {_summary.TotalPending:N0} تومان");
|
||||
sb.AppendLine($"تعداد کاربران یکتا: {_summary.UniqueUsers}");
|
||||
sb.AppendLine($"نرخ موفقیت: {_summary.SuccessRate:N2}%");
|
||||
sb.AppendLine();
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<PropertyColumn Property="x => x.Amount" Title="مبلغ">
|
||||
<CellTemplate>
|
||||
<MudText Typo="Typo.body2" Color="Color.Primary">
|
||||
<strong>@context.Item.Amount.ToString("N0") ریال</strong>
|
||||
<strong>@context.Item.Amount.ToString("N0") تومان</strong>
|
||||
</MudText>
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
|
||||
@@ -163,7 +163,7 @@ public partial class WithdrawalRequests
|
||||
{
|
||||
var confirmed = await DialogService.ShowMessageBox(
|
||||
"تایید درخواست",
|
||||
$"آیا از تایید درخواست برداشت {request.Amount:N0} ریال برای {request.UserName} مطمئن هستید؟",
|
||||
$"آیا از تایید درخواست برداشت {request.Amount:N0} تومان برای {request.UserName} مطمئن هستید؟",
|
||||
yesText: "تایید", cancelText: "لغو");
|
||||
|
||||
if (confirmed == true)
|
||||
@@ -222,7 +222,7 @@ public partial class WithdrawalRequests
|
||||
{
|
||||
var confirmed = await DialogService.ShowMessageBox(
|
||||
"پردازش پرداخت",
|
||||
$"آیا پرداخت {request.Amount:N0} ریال به {request.UserName} انجام شده است؟",
|
||||
$"آیا پرداخت {request.Amount:N0} تومان به {request.UserName} انجام شده است؟",
|
||||
yesText: "بله، پردازش شد", cancelText: "لغو");
|
||||
|
||||
if (confirmed == true)
|
||||
|
||||
@@ -32,10 +32,10 @@
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">مجموع فروش (۷ روز)</MudText>
|
||||
<MudText Typo="Typo.h5" Color="Color.Primary">
|
||||
@_stats.TotalSalesLast7Days.ToString("N0") ریال
|
||||
@_stats.TotalSalesLast7Days.ToString("N0") تومان
|
||||
</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">
|
||||
امروز: @_stats.TodaySales.ToString("N0") ریال
|
||||
امروز: @_stats.TodaySales.ToString("N0") تومان
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
@@ -43,7 +43,7 @@
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">میانگین مبلغ هر سفارش</MudText>
|
||||
<MudText Typo="Typo.h5">
|
||||
@_stats.AverageOrderAmount.ToString("N0") ریال
|
||||
@_stats.AverageOrderAmount.ToString("N0") تومان
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
|
||||
@@ -129,11 +129,11 @@
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
<MudTd>@context.Count</MudTd>
|
||||
<MudTd>@context.UnitPrice.ToString("N0") ریال</MudTd>
|
||||
<MudTd>@context.UnitPrice.ToString("N0") تومان</MudTd>
|
||||
<MudTd>
|
||||
<MudChip T="string" Size="Size.Small" Color="Color.Success">@context.MaxDiscountPercent%</MudChip>
|
||||
</MudTd>
|
||||
<MudTd><strong>@context.FinalPrice.ToString("N0") ریال</strong></MudTd>
|
||||
<MudTd><strong>@context.FinalPrice.ToString("N0") تومان</strong></MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudPaper>
|
||||
@@ -148,14 +148,14 @@
|
||||
<MudText Color="Color.Secondary">مبلغ کل:</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="6" Class="text-left">
|
||||
<MudText>@Order.TotalPrice.ToString("N0") ریال</MudText>
|
||||
<MudText>@Order.TotalPrice.ToString("N0") تومان</MudText>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="6">
|
||||
<MudText Color="Color.Success">از کیف پول تخفیف:</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="6" Class="text-left">
|
||||
<MudText Color="Color.Success">@Order.DiscountBalanceUsed.ToString("N0") ریال</MudText>
|
||||
<MudText Color="Color.Success">@Order.DiscountBalanceUsed.ToString("N0") تومان</MudText>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12"><MudDivider /></MudItem>
|
||||
@@ -165,7 +165,7 @@
|
||||
</MudItem>
|
||||
<MudItem xs="6" Class="text-left">
|
||||
<MudText Typo="Typo.h6" Color="Color.Primary">
|
||||
<strong>@Order.GatewayAmount.ToString("N0") ریال</strong>
|
||||
<strong>@Order.GatewayAmount.ToString("N0") تومان</strong>
|
||||
</MudText>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
Format="N0"
|
||||
Immediate="true"
|
||||
Disabled="_loading"
|
||||
Label="قیمت (ریال) *"
|
||||
Label="قیمت (تومان) *"
|
||||
Required="true"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" />
|
||||
|
||||
@@ -97,20 +97,20 @@
|
||||
|
||||
<TemplateColumn Title="مبلغ کل">
|
||||
<CellTemplate>
|
||||
<MudText>@context.Item.TotalPrice.ToString("N0") ریال</MudText>
|
||||
<MudText>@context.Item.TotalPrice.ToString("N0") تومان</MudText>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
|
||||
<TemplateColumn Title="تخفیف کیفپول">
|
||||
<CellTemplate>
|
||||
<MudText Color="Color.Success">@context.Item.DiscountBalanceUsed.ToString("N0") ریال</MudText>
|
||||
<MudText Color="Color.Success">@context.Item.DiscountBalanceUsed.ToString("N0") تومان</MudText>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
|
||||
<TemplateColumn Title="پرداخت درگاه">
|
||||
<CellTemplate>
|
||||
<MudText Typo="Typo.body2">
|
||||
<strong>@context.Item.GatewayAmount.ToString("N0") ریال</strong>
|
||||
<strong>@context.Item.GatewayAmount.ToString("N0") تومان</strong>
|
||||
</MudText>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
|
||||
<TemplateColumn Title="قیمت" CellStyle="text-wrap: nowrap;">
|
||||
<CellTemplate>
|
||||
<MudText>@context.Item.Price.ToString("N0") ریال</MudText>
|
||||
<MudText>@context.Item.Price.ToString("N0") تومان</MudText>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
|
||||
|
||||
@@ -113,19 +113,19 @@
|
||||
<MudItem xs="12" md="3">
|
||||
<MudPaper Elevation="1" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Success">مجموع فروش (مبلغ نهایی)</MudText>
|
||||
<MudText Typo="Typo.h5">@_totalSales.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.h5">@_totalSales.ToString("N0") تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="3">
|
||||
<MudPaper Elevation="1" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Warning">مجموع تخفیف</MudText>
|
||||
<MudText Typo="Typo.h5">@_totalDiscount.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.h5">@_totalDiscount.ToString("N0") تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="3">
|
||||
<MudPaper Elevation="1" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Info">میانگین مبلغ سفارش</MudText>
|
||||
<MudText Typo="Typo.h5">@_averageOrder.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.h5">@_averageOrder.ToString("N0") تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
@@ -242,12 +242,12 @@
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="مبلغ نهایی">
|
||||
<CellTemplate>
|
||||
@context.Item.GatewayAmount.ToString("N0") ریال
|
||||
@context.Item.GatewayAmount.ToString("N0") تومان
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="تخفیف">
|
||||
<CellTemplate>
|
||||
@context.Item.DiscountBalanceUsed.ToString("N0") ریال
|
||||
@context.Item.DiscountBalanceUsed.ToString("N0") تومان
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="وضعیت">
|
||||
@@ -566,9 +566,9 @@
|
||||
|
||||
sb.AppendLine("خلاصه:");
|
||||
sb.AppendLine($"تعداد سفارشها: {_totalOrders}");
|
||||
sb.AppendLine($"مجموع فروش (مبلغ نهایی): {_totalSales:N0} ریال");
|
||||
sb.AppendLine($"مجموع تخفیف: {_totalDiscount:N0} ریال");
|
||||
sb.AppendLine($"میانگین مبلغ سفارش: {_averageOrder:N0} ریال");
|
||||
sb.AppendLine($"مجموع فروش (مبلغ نهایی): {_totalSales:N0} تومان");
|
||||
sb.AppendLine($"مجموع تخفیف: {_totalDiscount:N0} تومان");
|
||||
sb.AppendLine($"میانگین مبلغ سفارش: {_averageOrder:N0} تومان");
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendLine("جزئیات سفارشها:");
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
<MudStack Spacing="0">
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">مبلغ کل استخر</MudText>
|
||||
<MudText Typo="Typo.h6" Color="Color.Primary">
|
||||
@(_currentPool?.TotalPoolAmount.ToString("N0") ?? "0") ریال
|
||||
@(_currentPool?.TotalPoolAmount.ToString("N0") ?? "0") تومان
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="x => x.PoolContribution" Title="سهم از استخر">
|
||||
<CellTemplate>
|
||||
@context.Item.PoolContribution.ToString("N0") ریال
|
||||
@context.Item.PoolContribution.ToString("N0") تومان
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="x => x.IsExpired" Title="وضعیت">
|
||||
|
||||
@@ -254,7 +254,7 @@
|
||||
<td><strong>کل کمیسیون کسب شده:</strong></td>
|
||||
<td>
|
||||
<MudText Typo="Typo.body1" Color="Color.Primary">
|
||||
<strong>@_userInfo.TotalEarnedCommission.ToString("N0") ریال</strong>
|
||||
<strong>@_userInfo.TotalEarnedCommission.ToString("N0") تومان</strong>
|
||||
</MudText>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -262,7 +262,7 @@
|
||||
<td><strong>کمیسیون پرداخت شده:</strong></td>
|
||||
<td>
|
||||
<MudText Typo="Typo.body1" Color="Color.Success">
|
||||
@_userInfo.TotalPaidCommission.ToString("N0") ریال
|
||||
@_userInfo.TotalPaidCommission.ToString("N0") تومان
|
||||
</MudText>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -270,7 +270,7 @@
|
||||
<td><strong>کمیسیون در انتظار:</strong></td>
|
||||
<td>
|
||||
<MudText Typo="Typo.body1" Color="Color.Warning">
|
||||
@_userInfo.PendingCommission.ToString("N0") ریال
|
||||
@_userInfo.PendingCommission.ToString("N0") تومان
|
||||
</MudText>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
<MudText Typo="Typo.h6">جزئیات فعالسازی دستی</MudText>
|
||||
<MudText Typo="Typo.body2">شناسه: @Model.Id</MudText>
|
||||
<MudText Typo="Typo.body2">کاربر: @Model.UserFullName (@Model.UserId)</MudText>
|
||||
<MudText Typo="Typo.body2">مبلغ: @Model.Amount.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.body2">مبلغ: @Model.Amount.ToString("N0") تومان</MudText>
|
||||
<MudText Typo="Typo.body2">نوع: @Model.TypeDisplay</MudText>
|
||||
<MudText Typo="Typo.body2">وضعیت: @Model.StatusDisplay</MudText>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<MudText Typo="Typo.h6">جزئیات تراکنش</MudText>
|
||||
<MudText Typo="Typo.body2">شناسه: @Model.Id</MudText>
|
||||
<MudText Typo="Typo.body2">RefId: @Model.RefId</MudText>
|
||||
<MudText Typo="Typo.body2">مبلغ: @Model.Amount.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.body2">مبلغ: @Model.Amount.ToString("N0") تومان</MudText>
|
||||
<MudText Typo="Typo.body2">وضعیت: @StatusText</MudText>
|
||||
<MudText Typo="Typo.body2">تاریخ پرداخت: @Model.PaymentDate.ToLocalTime().MiladiToJalaliWithTime()</MudText>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
{
|
||||
bool? confirm = await DialogService.ShowMessageBox(
|
||||
"تایید پرداخت",
|
||||
$"آیا از تایید پرداخت دستی #{model.Id} به مبلغ {model.Amount:N0} ریال مطمئن هستید؟",
|
||||
$"آیا از تایید پرداخت دستی #{model.Id} به مبلغ {model.Amount:N0} تومان مطمئن هستید؟",
|
||||
yesText: "تایید", cancelText: "لغو");
|
||||
if (confirm == true)
|
||||
{
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
|
||||
<MudNumericField T="long?"
|
||||
HideSpinButtons="true"
|
||||
Label="قیمت جدید (ریال)"
|
||||
Label="قیمت جدید (تومان)"
|
||||
@bind-Value="_newPrice"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" />
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<MudTextField T="string" @bind-Value="Model.Title" Disabled="_isLoading" Label="عنوان" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudNumericField T="long" HideSpinButtons="true" @bind-Value="Model.Price" Format="N0" Immediate="true" Disabled="_isLoading" Label="قیمت (ریال)" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudNumericField T="long" HideSpinButtons="true" @bind-Value="Model.Price" Format="N0" Immediate="true" Disabled="_isLoading" Label="قیمت (تومان)" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
</MudStack>
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<MudTextField T="string" @bind-Value="Model.Title" Disabled="_isLoading" Label="عنوان" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudNumericField T="long" HideSpinButtons="true" @bind-Value="Model.Price" Format="N0" Immediate="true" Disabled="_isLoading" Label="قیمت (ریال)" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudNumericField T="long" HideSpinButtons="true" @bind-Value="Model.Price" Format="N0" Immediate="true" Disabled="_isLoading" Label="قیمت (تومان)" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
</MudStack>
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
<TemplateColumn Title="قیمت" CellStyle="text-wrap: nowrap;">
|
||||
<CellTemplate>
|
||||
@context.Item.Price.ToString("N0") ریال
|
||||
@context.Item.Price.ToString("N0") تومان
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
</MudText>
|
||||
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">
|
||||
مبلغ تخفیف بهصورت ریالی وارد شود.
|
||||
مبلغ تخفیف بهصورت تومانی وارد شود.
|
||||
</MudText>
|
||||
|
||||
<MudNumericField T="long?"
|
||||
@bind-Value="_discountAmount"
|
||||
Label="مبلغ تخفیف (ریال)"
|
||||
Label="مبلغ تخفیف (تومان)"
|
||||
Variant="Variant.Outlined"
|
||||
HideSpinButtons="true" />
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ public partial class ApplyDiscountDialog
|
||||
|
||||
if (response.Success)
|
||||
{
|
||||
Snackbar.Add($"تخفیف با موفقیت اعمال شد. مبلغ نهایی: {response.FinalAmount.ToString("N0")} ریال", Severity.Success);
|
||||
Snackbar.Add($"تخفیف با موفقیت اعمال شد. مبلغ نهایی: {response.FinalAmount.ToString("N0")} تومان", Severity.Success);
|
||||
MudDialog.Close(DialogResult.Ok(true));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -113,13 +113,13 @@
|
||||
<MudItem xs="12" md="3">
|
||||
<MudPaper Elevation="1" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Success">مجموع فروش</MudText>
|
||||
<MudText Typo="Typo.h5">@_totalSales.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.h5">@_totalSales.ToString("N0") تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="3">
|
||||
<MudPaper Elevation="1" Class="pa-4 text-center">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Info">میانگین مبلغ سفارش</MudText>
|
||||
<MudText Typo="Typo.h5">@_averageOrder.ToString("N0") ریال</MudText>
|
||||
<MudText Typo="Typo.h5">@_averageOrder.ToString("N0") تومان</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="3">
|
||||
@@ -237,7 +237,7 @@
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="مبلغ">
|
||||
<CellTemplate>
|
||||
@context.Item.Amount.ToString("N0") ریال
|
||||
@context.Item.Amount.ToString("N0") تومان
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="وضعیت پرداخت">
|
||||
|
||||
@@ -279,8 +279,8 @@ public partial class OrderSalesReports
|
||||
|
||||
sb.AppendLine("خلاصه:");
|
||||
sb.AppendLine($"تعداد سفارشها: {_totalOrders}");
|
||||
sb.AppendLine($"مجموع فروش: {_totalSales:N0} ریال");
|
||||
sb.AppendLine($"میانگین مبلغ سفارش: {_averageOrder:N0} ریال");
|
||||
sb.AppendLine($"مجموع فروش: {_totalSales:N0} تومان");
|
||||
sb.AppendLine($"میانگین مبلغ سفارش: {_averageOrder:N0} تومان");
|
||||
sb.AppendLine($"پرداخت شده: {_paidCount}");
|
||||
sb.AppendLine();
|
||||
|
||||
|
||||
@@ -30,15 +30,22 @@
|
||||
</ToolBarContent>
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.Id" Title="شناسه" />
|
||||
<PropertyColumn Property="x => x.UserId" Title="کاربر" />
|
||||
<PropertyColumn Property="x => x.UserId" Title="کاربر">
|
||||
<CellTemplate>
|
||||
<MudStack Spacing="0">
|
||||
<MudText Typo="Typo.body2"><strong>@context.Item.UserName</strong></MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">ID: @context.Item.UserId</MudText>
|
||||
</MudStack>
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
<TemplateColumn Title="موجودی اصلی">
|
||||
<CellTemplate>
|
||||
<MudText Color="Color.Primary"><strong>@context.Item.Balance.ToString("N0")</strong> ریال</MudText>
|
||||
<MudText Color="Color.Primary"><strong>@context.Item.Balance.ToString("N0")</strong> تومان</MudText>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="موجودی شبکه">
|
||||
<CellTemplate>
|
||||
<MudText Color="Color.Success">@context.Item.NetworkBalance.ToString("N0") ریال</MudText>
|
||||
<MudText Color="Color.Success">@context.Item.NetworkBalance.ToString("N0") تومان</MudText>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="عملیات" Sortable="false">
|
||||
|
||||
Reference in New Issue
Block a user