diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantMobile.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantMobile.razor
index 70e849a9..6e7c57a5 100644
--- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantMobile.razor
+++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantMobile.razor
@@ -5,98 +5,138 @@
@page "/pos/restaurant/mobile"
@layout PosLayout
@inherits PosBase
+@inject WebClientTpos.Client.Services.PosDataService DataService
- @* ═══ HEADER / TIÊU ĐỀ ═══ *@
-
- Sơ đồ bàn
- @_tables.Count bàn
-
+ @if (_isLoading)
+ {
+
+ Đang tải...
+
+ }
+ else if (_loadError)
+ {
+
+ Không thể tải dữ liệu
+
+ }
+ else
+ {
+ @* ═══ HEADER / TIÊU ĐỀ ═══ *@
+
+ Sơ đồ bàn
+ @_tables.Count bàn
+
- @* ═══ SECTION FILTER / LỌC KHU VỰC ═══ *@
-
- @foreach (var s in _sections)
- {
-
- }
-
+ @* ═══ SECTION FILTER / LỌC KHU VỰC ═══ *@
+
+ @foreach (var s in _sections)
+ {
+
+ }
+
- @* ═══ TABLE LIST / DANH SÁCH BÀN ═══ *@
-
- @foreach (var t in FilteredTables)
- {
-
OpenTable(t)"
- style="background:var(--pos-bg-elevated);border-radius:var(--pos-radius);padding:14px 16px;
- display:flex;align-items:center;gap:12px;cursor:pointer;
- border-left:4px solid @StatusColor(t.Status);">
- @* EN: Table number badge / VI: Badge số bàn *@
-
- @t.Number
-
-
-
@t.Name
-
- @t.Seats chỗ · @t.Section
+ @* ═══ TABLE LIST / DANH SÁCH BÀN ═══ *@
+
+ @foreach (var t in FilteredTables)
+ {
+
OpenTable(t)"
+ style="background:var(--pos-bg-elevated);border-radius:var(--pos-radius);padding:14px 16px;
+ display:flex;align-items:center;gap:12px;cursor:pointer;
+ border-left:4px solid @StatusColor(t.Status);">
+ @* EN: Table number badge / VI: Badge số bàn *@
+
+ @t.Number
-
-
-
- @StatusLabel(t.Status)
-
- @if (t.Status == "occupied")
- {
-
- @FormatPrice(t.Amount)
+
+
@t.Name
+
+ @t.Seats chỗ · @t.Section
- }
+
+
+
+ @StatusLabel(t.Status)
+
+ @if (t.Status == "occupied")
+ {
+
+ @FormatPrice(t.Amount)
+
+ }
+
+
-
-
- }
-
+ }
+
- @* ═══ BOTTOM STATS / THỐNG KÊ DƯỚI ═══ *@
-
-
-
@_tables.Count(t => t.Status == "available")
-
Trống
+ @* ═══ BOTTOM STATS / THỐNG KÊ DƯỚI ═══ *@
+
+
+
@_tables.Count(t => t.Status == "available")
+
Trống
+
+
+
@_tables.Count(t => t.Status == "occupied")
+
Đang phục vụ
+
+
+
@_tables.Count(t => t.Status == "reserved")
+
Đã đặt
+
-
-
@_tables.Count(t => t.Status == "occupied")
-
Đang phục vụ
-
-
-
@_tables.Count(t => t.Status == "reserved")
-
Đã đặt
-
-
+ }
@code {
- private string _activeSection = "Tất cả";
- private readonly string[] _sections = { "Tất cả", "Trong nhà", "Ngoài trời", "VIP" };
+ // EN: Restaurant shop ID / VI: ID cửa hàng nhà hàng
+ private static readonly Guid RestaurantShopId = Guid.Parse("b0000002-0000-0000-0000-000000000002");
- // EN: Demo tables / VI: Bàn mẫu
- private readonly List
_tables = new()
- {
- new(1, "Bàn 1", 4, "available", "Trong nhà", 0),
- new(2, "Bàn 2", 2, "occupied", "Trong nhà", 195_000),
- new(3, "Bàn 3", 6, "occupied", "Trong nhà", 420_000),
- new(4, "Bàn 4", 4, "reserved", "VIP", 0),
- new(5, "Bàn 5", 8, "available", "VIP", 0),
- new(6, "Bàn 6", 4, "occupied", "Ngoài trời", 310_000),
- new(7, "Bàn 7", 4, "available", "Ngoài trời", 0),
- new(8, "Bàn 8", 10, "reserved", "VIP", 0),
- new(9, "Bàn 9", 2, "available", "Trong nhà", 0),
- new(10, "Bàn 10", 4, "occupied", "Ngoài trời", 175_000),
- };
+ // EN: Loading state / VI: Trạng thái tải
+ private bool _isLoading = true;
+ private bool _loadError;
+
+ // EN: Active section filter / VI: Bộ lọc khu vực
+ private string _activeSection = "Tất cả";
+ private string[] _sections = { "Tất cả" };
+
+ // EN: Table data from API / VI: Dữ liệu bàn từ API
+ private List _tables = new();
private IEnumerable FilteredTables =>
_activeSection == "Tất cả" ? _tables : _tables.Where(t => t.Section == _activeSection);
+ protected override async Task OnInitializedAsync()
+ {
+ try
+ {
+ var apiTables = await DataService.GetTablesAsync(RestaurantShopId);
+
+ _tables = apiTables.Select(t => new MobileTable(
+ int.TryParse(t.TableNumber, out var num) ? num : 0,
+ $"Bàn {t.TableNumber}",
+ t.Capacity,
+ t.Status ?? "available",
+ t.Zone ?? "Trong nhà",
+ 0
+ )).ToList();
+
+ var zones = _tables.Select(t => t.Section).Distinct().ToList();
+ _sections = new[] { "Tất cả" }.Concat(zones).ToArray();
+ }
+ catch
+ {
+ _loadError = true;
+ }
+ finally
+ {
+ _isLoading = false;
+ }
+ }
+
private void OpenTable(MobileTable t) => NavigateTo("restaurant/waiter-pad");
private static string StatusColor(string s) => s switch
diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantTablet.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantTablet.razor
index e72435e8..6f9df994 100644
--- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantTablet.razor
+++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantTablet.razor
@@ -5,34 +5,50 @@
@page "/pos/restaurant/tablet"
@layout PosLayout
@inherits PosBase
+@inject WebClientTpos.Client.Services.PosDataService DataService
- @* ═══ SECTION FILTER / LỌC KHU VỰC ═══ *@
-
- @foreach (var s in _sections)
- {
-
- }
-
+ @if (_isLoading)
+ {
+
+ Đang tải...
+
+ }
+ else if (_loadError)
+ {
+
+ Không thể tải dữ liệu
+
+ }
+ else
+ {
+ @* ═══ SECTION FILTER / LỌC KHU VỰC ═══ *@
+
+ @foreach (var s in _sections)
+ {
+
+ }
+
- @* ═══ TABLE MAP / SƠ ĐỒ BÀN ═══ *@
-
- @foreach (var t in FilteredTables)
- {
-
_selected = t"
- style="background:@StatusBg(t.Status);border-radius:var(--pos-radius);padding:20px;
- text-align:center;cursor:pointer;min-height:100px;display:flex;flex-direction:column;
- align-items:center;justify-content:center;gap:6px;
- border:3px solid @(_selected?.Id == t.Id ? "var(--pos-orange-primary)" : "transparent");
- transition:all .2s ease;">
- @t.Name
- @t.Seats chỗ
- @StatusLabel(t.Status)
-
- }
-
+ @* ═══ TABLE MAP / SƠ ĐỒ BÀN ═══ *@
+
+ @foreach (var t in FilteredTables)
+ {
+
_selected = t"
+ style="background:@StatusBg(t.Status);border-radius:var(--pos-radius);padding:20px;
+ text-align:center;cursor:pointer;min-height:100px;display:flex;flex-direction:column;
+ align-items:center;justify-content:center;gap:6px;
+ border:3px solid @(_selected?.Id == t.Id ? "var(--pos-orange-primary)" : "transparent");
+ transition:all .2s ease;">
+ @t.Name
+ @t.Seats chỗ
+ @StatusLabel(t.Status)
+
+ }
+
+ }
@* ═══ ORDER SIDEBAR / SIDEBAR ĐẶT MÓN ═══ *@
@@ -85,28 +101,60 @@
@code {
+ // EN: Restaurant shop ID / VI: ID cửa hàng nhà hàng
+ private static readonly Guid RestaurantShopId = Guid.Parse("b0000002-0000-0000-0000-000000000002");
+
+ // EN: Loading state / VI: Trạng thái tải
+ private bool _isLoading = true;
+ private bool _loadError;
+
+ // EN: Active section filter / VI: Bộ lọc khu vực
private string _activeSection = "Tất cả";
- private readonly string[] _sections = { "Tất cả", "Trong nhà", "Ngoài trời", "VIP" };
+ private string[] _sections = { "Tất cả" };
+
+ // EN: Selected table reference / VI: Bàn đang chọn
private TableInfo? _selected;
- private readonly List
_tables = new()
- {
- new("T01","Bàn 1", 4, "available", "Trong nhà"), new("T02","Bàn 2", 2, "occupied", "Trong nhà"),
- new("T03","Bàn 3", 6, "occupied", "Trong nhà"), new("T04","Bàn 4", 4, "reserved", "VIP"),
- new("T05","Bàn 5", 8, "available", "VIP"), new("T06","Bàn 6", 4, "available", "Ngoài trời"),
- new("T07","Bàn 7", 4, "occupied", "Ngoài trời"), new("T08","Bàn 8", 2, "available", "Ngoài trời"),
- new("T09","Bàn 9", 10, "reserved", "VIP"), new("T10","Bàn 10", 6, "occupied", "Trong nhà"),
- };
+ // EN: Table data from API / VI: Dữ liệu bàn từ API
+ private List _tables = new();
private IEnumerable FilteredTables =>
_activeSection == "Tất cả" ? _tables : _tables.Where(t => t.Section == _activeSection);
+ // EN: Demo order items for occupied tables / VI: Món mẫu cho bàn đang phục vụ
private readonly List _items = new()
{
new("Bún bò Huế", 80_000, 1), new("Nem rán", 50_000, 2),
new("Cá kho tộ", 120_000, 1), new("Nước mía", 15_000, 2),
};
+ protected override async Task OnInitializedAsync()
+ {
+ try
+ {
+ var apiTables = await DataService.GetTablesAsync(RestaurantShopId);
+
+ _tables = apiTables.Select(t => new TableInfo(
+ t.Id.ToString(),
+ $"Bàn {t.TableNumber}",
+ t.Capacity,
+ t.Status ?? "available",
+ t.Zone ?? "Trong nhà"
+ )).ToList();
+
+ var zones = _tables.Select(t => t.Section).Distinct().ToList();
+ _sections = new[] { "Tất cả" }.Concat(zones).ToArray();
+ }
+ catch
+ {
+ _loadError = true;
+ }
+ finally
+ {
+ _isLoading = false;
+ }
+ }
+
private static string StatusBg(string s) => s switch
{
"available" => "rgba(34,197,94,.15)", "occupied" => "rgba(255,92,0,.18)",
diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/KitchenDisplay.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/KitchenDisplay.razor
index 8a83e55b..d967fb1b 100644
--- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/KitchenDisplay.razor
+++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/KitchenDisplay.razor
@@ -5,6 +5,7 @@
@page "/pos/restaurant/kitchen-display"
@layout PosLayout
@inherits PosBase
+@inject WebClientTpos.Client.Services.PosDataService DataService
@* ═══ HEADER / TIÊU ĐỀ ═══ *@
@@ -23,6 +24,20 @@
@* ═══ TICKET COLUMNS / CỘT PHIẾU ═══ *@
+ @if (_isLoading)
+ {
+
+ Đang tải...
+
+ }
+ else if (_loadError)
+ {
+
+ Không thể tải dữ liệu
+
+ }
+ else
+ {
@foreach (var status in _statuses)
{
@@ -91,15 +106,23 @@
}
+ }
@code {
+ // EN: Restaurant shop ID / VI: ID cửa hàng nhà hàng
+ private static readonly Guid RestaurantShopId = Guid.Parse("b0000002-0000-0000-0000-000000000002");
+
+ // EN: Loading state / VI: Trạng thái tải
+ private bool _isLoading = true;
+ private bool _loadError;
+
private readonly Dictionary
_statuses = new()
{
["new"] = "Mới", ["cooking"] = "Đang nấu", ["ready"] = "Sẵn sàng"
};
- // EN: Demo kitchen tickets / VI: Phiếu bếp mẫu
+ // EN: Demo kitchen tickets — needs kitchen_tickets API / VI: Phiếu bếp mẫu — cần API kitchen_tickets
private readonly List _tickets = new()
{
new("Bàn 2", "new", 2, new() { new(2, "Gỏi cuốn", ""), new(1, "Phở bò tái", "Ít hành") }),
@@ -110,6 +133,24 @@
new("Bàn 10", "ready", 8, new() { new(2, "Cơm tấm sườn", ""), new(1, "Cà phê sữa", "") }),
};
+ protected override async Task OnInitializedAsync()
+ {
+ try
+ {
+ // EN: Preload tables for reference — kitchen_tickets API not yet available
+ // VI: Tải trước bàn để tham chiếu — API kitchen_tickets chưa có
+ await DataService.GetTablesAsync(RestaurantShopId);
+ }
+ catch
+ {
+ _loadError = true;
+ }
+ finally
+ {
+ _isLoading = false;
+ }
+ }
+
private static string ColumnBg(string s) => s switch
{
"new" => "rgba(239,68,68,.15)", "cooking" => "rgba(245,158,11,.15)",
diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/OrderHistory.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/OrderHistory.razor
index 068deb0e..10937e34 100644
--- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/OrderHistory.razor
+++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/OrderHistory.razor
@@ -5,6 +5,7 @@
@page "/pos/restaurant/order-history"
@layout PosLayout
@inherits PosBase
+@inject WebClientTpos.Client.Services.PosDataService DataService
@* ═══ HEADER / TIÊU ĐỀ ═══ *@
@@ -36,6 +37,20 @@
@* ═══ ORDER LIST / DANH SÁCH ĐƠN ═══ *@
+ @if (_isLoading)
+ {
+
+ Đang tải...
+
+ }
+ else if (_loadError)
+ {
+
+ Không thể tải dữ liệu
+
+ }
+ else
+ {
@foreach (var order in FilteredOrders)
{
_expandedId = _expandedId == order.Id ? null : order.Id"
@@ -82,6 +97,7 @@
}
}
+ }
@* ═══ FOOTER SUMMARY / TỔNG KẾT ═══ *@
@@ -93,12 +109,19 @@
@code {
+ // EN: Restaurant shop ID / VI: ID cửa hàng nhà hàng
+ private static readonly Guid RestaurantShopId = Guid.Parse("b0000002-0000-0000-0000-000000000002");
+
+ // EN: Loading state / VI: Trạng thái tải
+ private bool _isLoading = true;
+ private bool _loadError;
+
private string _searchQuery = string.Empty;
private string _activeFilter = "Tất cả";
private string? _expandedId;
private readonly string[] _filters = { "Tất cả", "Tiền mặt", "Thẻ", "Chuyển khoản" };
- // EN: Demo order history / VI: Lịch sử đơn mẫu
+ // EN: Demo order history — needs orders API / VI: Lịch sử đơn mẫu — cần API orders
private readonly List _orders = new()
{
new("DH001", "B3", "10:15", "Nguyễn Văn A", 3, 285_000, "Tiền mặt",
@@ -119,6 +142,24 @@
new() { new("Bún bò Huế", 80_000, 2), new("Gỏi cuốn", 45_000, 2), new("Cà phê sữa", 29_000, 2), new("Bánh flan", 25_000, 2) }),
};
+ protected override async Task OnInitializedAsync()
+ {
+ try
+ {
+ // EN: Preload tables for reference — orders API not yet available
+ // VI: Tải trước bàn để tham chiếu — API orders chưa có
+ await DataService.GetTablesAsync(RestaurantShopId);
+ }
+ catch
+ {
+ _loadError = true;
+ }
+ finally
+ {
+ _isLoading = false;
+ }
+ }
+
private IEnumerable FilteredOrders
{
get
diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/RestaurantMenuManagement.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/RestaurantMenuManagement.razor
index 369ef120..18399e41 100644
--- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/RestaurantMenuManagement.razor
+++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/Workflow/RestaurantMenuManagement.razor
@@ -5,6 +5,7 @@
@page "/pos/restaurant/menu-management"
@layout PosLayout
@inherits PosBase
+@inject WebClientTpos.Client.Services.PosDataService DataService
@* ═══ HEADER / TIÊU ĐỀ ═══ *@
@@ -53,6 +54,20 @@
@* ═══ MENU ITEM GRID / LƯỚI MÓN ═══ *@
+ @if (_isLoading)
+ {
+
+ Đang tải...
+
+ }
+ else if (_loadError)
+ {
+
+ Không thể tải dữ liệu
+
+ }
+ else
+ {
@foreach (var item in FilteredMenu)
{
@@ -92,6 +107,7 @@
}
+ }
@* ═══ STATS BAR / THANH THỐNG KÊ ═══ *@
@@ -104,30 +120,52 @@
@code {
- private string _activeCategory = "Khai vị";
+ // EN: Restaurant shop ID / VI: ID cửa hàng nhà hàng
+ private static readonly Guid RestaurantShopId = Guid.Parse("b0000002-0000-0000-0000-000000000002");
+
+ // EN: Loading state / VI: Trạng thái tải
+ private bool _isLoading = true;
+ private bool _loadError;
+
+ private string _activeCategory = "Tất cả";
private bool _editMode = false;
private string? _selectedItem;
- private readonly string[] _categories = { "Khai vị", "Món chính", "Lẩu", "Nước", "Tráng miệng" };
+ private string[] _categories = { "Tất cả" };
- // EN: Menu items / VI: Các món trong thực đơn
- private readonly List