feat(admin): P2 features — Calendar, KDS, Room types, Medical, Receipt
- S5: Appointment calendar view (7-day grid, week nav, today highlight) - R2: Kitchen Display demo with station tabs (Bếp/Bar/Nướng) - K4: Room type badges (VIP/Standard/Party) from zone field - B2: Treatments tabbed view (Liệu trình/Hồ sơ y tế/Ảnh Before-After) - G10: Receipt settings panel (header/footer, paper size, logo, QR code) - Added _calendarWeekOffset, _kdsStation, _treatmentTab state vars
This commit is contained in:
@@ -490,18 +490,23 @@
|
||||
<span class="admin-status-badge admin-status-badge--paused" style="font-size:11px;"><span class="admin-status-badge__dot"></span>Đang hát: @_tables.Count(t => t.Status == "occupied")</span>
|
||||
<span class="admin-status-badge admin-status-badge--setup" style="font-size:11px;"><span class="admin-status-badge__dot"></span>Đã đặt: @_tables.Count(t => t.Status == "reserved")</span>
|
||||
</div>
|
||||
<div style="font-size:12px;color:var(--admin-text-tertiary);">@_tables.Count phòng</div>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px;">
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:16px;">
|
||||
@foreach (var room in _tables)
|
||||
{
|
||||
var bgColor = room.Status switch { "available" => "rgba(139,92,246,0.08)", "occupied" => "rgba(239,68,68,0.08)", "reserved" => "rgba(245,158,11,0.08)", _ => "rgba(107,107,111,0.08)" };
|
||||
var borderColor = room.Status switch { "available" => "rgba(139,92,246,0.3)", "occupied" => "rgba(239,68,68,0.3)", "reserved" => "rgba(245,158,11,0.3)", _ => "rgba(107,107,111,0.3)" };
|
||||
var statusColor = room.Status switch { "available" => "#8B5CF6", "occupied" => "#EF4444", "reserved" => "#F59E0B", _ => "#6B6B6F" };
|
||||
var statusText = room.Status switch { "available" => "Trống", "occupied" => "Đang hát", "reserved" => "Đã đặt", "cleaning" => "Dọn dẹp", _ => room.Status };
|
||||
var roomType = (room.Zone ?? "").ToLower() switch { var z when z.Contains("vip") => ("VIP", "#F59E0B"), var z when z.Contains("party") => ("Party", "#EC4899"), _ => ("Standard", "#8B5CF6") };
|
||||
<div style="background:@bgColor;border:1px solid @borderColor;border-radius:14px;padding:20px;">
|
||||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;">
|
||||
<i data-lucide="door-open" style="width:20px;height:20px;color:@statusColor;"></i>
|
||||
<span style="font-size:18px;font-weight:700;">Phòng @room.TableNumber</span>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">
|
||||
<div style="display:flex;align-items:center;gap:10px;">
|
||||
<i data-lucide="door-open" style="width:20px;height:20px;color:@statusColor;"></i>
|
||||
<span style="font-size:18px;font-weight:700;">Phòng @room.TableNumber</span>
|
||||
</div>
|
||||
<span style="font-size:10px;font-weight:700;padding:2px 8px;border-radius:6px;background:@($"{roomType.Item2}22");color:@roomType.Item2;">@roomType.Item1</span>
|
||||
</div>
|
||||
<div style="font-size:12px;color:var(--admin-text-tertiary);margin-bottom:8px;">@(room.Zone ?? "Chung") • @room.Capacity chỗ</div>
|
||||
<div style="display:inline-flex;align-items:center;gap:4px;font-size:11px;font-weight:600;color:@statusColor;">
|
||||
@@ -520,39 +525,57 @@
|
||||
}
|
||||
break;
|
||||
|
||||
// ═══ APPOINTMENTS (Spa / Thẩm mỹ) ═══
|
||||
// ═══ APPOINTMENTS (Spa / Thẩm mỹ) — Calendar View ═══
|
||||
case "appointments":
|
||||
@if (!_appointments.Any())
|
||||
{
|
||||
@RenderEmpty("calendar", "#EC4899", "Chưa có lịch hẹn", "Lịch hẹn sẽ hiển thị khi khách đặt dịch vụ", "plus-circle", "Tạo lịch hẹn", $"/admin/shop/{ShopId}/appointments")
|
||||
}
|
||||
else
|
||||
{
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px;margin-bottom:16px;">
|
||||
var calWeekStart = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + 1 + _calendarWeekOffset * 7);
|
||||
var calWeekEnd = calWeekStart.AddDays(7);
|
||||
var weekAppts = _appointments.Where(a => a.StartTime >= calWeekStart && a.StartTime < calWeekEnd).ToList();
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;">
|
||||
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:12px;">
|
||||
<div class="admin-stat-card"><div class="admin-stat-card__icon" style="background:rgba(236,72,153,0.1);"><i data-lucide="calendar" style="color:#EC4899;"></i></div><div class="admin-stat-card__content"><span class="admin-stat-card__value">@_appointments.Count</span><span class="admin-stat-card__label">Tổng lịch hẹn</span></div></div>
|
||||
<div class="admin-stat-card"><div class="admin-stat-card__icon" style="background:rgba(34,197,94,0.1);"><i data-lucide="check-circle" style="color:#22C55E;"></i></div><div class="admin-stat-card__content"><span class="admin-stat-card__value">@_appointments.Count(a => a.Status == "Confirmed")</span><span class="admin-stat-card__label">Đã xác nhận</span></div></div>
|
||||
<div class="admin-stat-card"><div class="admin-stat-card__icon" style="background:rgba(245,158,11,0.1);"><i data-lucide="clock" style="color:#F59E0B;"></i></div><div class="admin-stat-card__content"><span class="admin-stat-card__value">@_appointments.Count(a => a.Status == "Pending")</span><span class="admin-stat-card__label">Chờ xác nhận</span></div></div>
|
||||
<div class="admin-stat-card"><div class="admin-stat-card__icon" style="background:rgba(59,130,246,0.1);"><i data-lucide="calendar-range" style="color:#3B82F6;"></i></div><div class="admin-stat-card__content"><span class="admin-stat-card__value">@weekAppts.Count</span><span class="admin-stat-card__label">Tuần này</span></div></div>
|
||||
</div>
|
||||
<div class="admin-panel">
|
||||
<div class="admin-panel__body" style="padding:0;">
|
||||
<table class="admin-table" style="width:100%;"><thead><tr>
|
||||
<th style="padding:12px 16px;text-align:left;font-size:12px;text-transform:uppercase;color:var(--admin-text-tertiary);">Thời gian</th>
|
||||
<th style="padding:12px 16px;text-align:left;font-size:12px;text-transform:uppercase;color:var(--admin-text-tertiary);">Phòng / Tài nguyên</th>
|
||||
<th style="padding:12px 16px;text-align:left;font-size:12px;text-transform:uppercase;color:var(--admin-text-tertiary);">Trạng thái</th>
|
||||
</tr></thead><tbody>
|
||||
@foreach (var a in _appointments.OrderBy(a => a.StartTime))
|
||||
{
|
||||
var statusColor = a.Status switch { "Confirmed" => "#22C55E", "Pending" => "#F59E0B", "Completed" => "#3B82F6", "Cancelled" => "#EF4444", _ => "#6B6B6F" };
|
||||
<tr style="border-top:1px solid var(--admin-border-subtle);">
|
||||
<td style="padding:12px 16px;"><div style="font-weight:600;font-size:13px;">@a.StartTime.ToString("dd/MM/yyyy")</div><div style="font-size:11px;color:var(--admin-text-tertiary);">@a.StartTime.ToString("HH:mm") — @a.EndTime.ToString("HH:mm")</div></td>
|
||||
<td style="padding:12px 16px;font-size:13px;">@(a.ResourceName ?? "—")</td>
|
||||
<td style="padding:12px 16px;"><span style="display:inline-flex;align-items:center;gap:4px;font-size:11px;font-weight:600;color:@statusColor;"><span style="width:6px;height:6px;border-radius:50%;background:@statusColor;"></span>@a.Status</span></td>
|
||||
</tr>
|
||||
}
|
||||
</tbody></table>
|
||||
</div>
|
||||
<div class="admin-panel">
|
||||
<div class="admin-panel__header" style="display:flex;justify-content:space-between;align-items:center;">
|
||||
<h3 style="margin:0;font-size:14px;font-weight:700;">Lịch hẹn tuần @calWeekStart.ToString("dd/MM") — @calWeekEnd.AddDays(-1).ToString("dd/MM")</h3>
|
||||
<div style="display:flex;gap:4px;">
|
||||
<button @onclick='() => { _calendarWeekOffset--; StateHasChanged(); }' style="padding:6px 12px;border-radius:8px;border:1px solid var(--admin-border-subtle);background:var(--admin-bg-elevated);color:var(--admin-text-primary);font-size:12px;cursor:pointer;">← Trước</button>
|
||||
<button @onclick='() => { _calendarWeekOffset = 0; StateHasChanged(); }' style="padding:6px 12px;border-radius:8px;border:1px solid var(--admin-orange-primary);background:rgba(255,92,0,0.1);color:var(--admin-orange-primary);font-size:12px;font-weight:600;cursor:pointer;">Hôm nay</button>
|
||||
<button @onclick='() => { _calendarWeekOffset++; StateHasChanged(); }' style="padding:6px 12px;border-radius:8px;border:1px solid var(--admin-border-subtle);background:var(--admin-bg-elevated);color:var(--admin-text-primary);font-size:12px;cursor:pointer;">Sau →</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="admin-panel__body" style="padding:0;">
|
||||
<div style="display:grid;grid-template-columns:repeat(7,1fr);min-height:300px;">
|
||||
@for (int d = 0; d < 7; d++)
|
||||
{
|
||||
var day = calWeekStart.AddDays(d);
|
||||
var dayAppts = weekAppts.Where(a => a.StartTime.Date == day.Date).OrderBy(a => a.StartTime).ToList();
|
||||
var isToday = day.Date == DateTime.Today;
|
||||
<div style="border-right:1px solid var(--admin-border-subtle);padding:8px;@(d == 6 ? "border-right:none;" : "")">
|
||||
<div style="text-align:center;padding:6px 0;margin-bottom:8px;border-radius:8px;@(isToday ? "background:rgba(255,92,0,0.15);" : "")">
|
||||
<div style="font-size:11px;font-weight:600;color:var(--admin-text-tertiary);">@DayLabel((int)day.DayOfWeek)</div>
|
||||
<div style="font-size:16px;font-weight:700;@(isToday ? "color:var(--admin-orange-primary);" : "")">@day.Day</div>
|
||||
</div>
|
||||
@foreach (var appt in dayAppts)
|
||||
{
|
||||
var apptColor = appt.Status switch { "Confirmed" => "#22C55E", "Pending" => "#F59E0B", "Completed" => "#3B82F6", _ => "#6B6B6F" };
|
||||
<div style="background:@($"{apptColor}15");border-left:3px solid @apptColor;border-radius:6px;padding:6px 8px;margin-bottom:4px;font-size:11px;">
|
||||
<div style="font-weight:600;">@appt.StartTime.ToString("HH:mm")-@appt.EndTime.ToString("HH:mm")</div>
|
||||
<div style="color:var(--admin-text-tertiary);margin-top:2px;">@(appt.ResourceName ?? "—")</div>
|
||||
</div>
|
||||
}
|
||||
@if (!dayAppts.Any())
|
||||
{
|
||||
<div style="text-align:center;padding:20px 0;font-size:11px;color:var(--admin-text-quaternary, #555);">—</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
break;
|
||||
|
||||
// ═══ SERVICES (Spa — products with type=Service) ═══
|
||||
@@ -664,16 +687,53 @@
|
||||
}
|
||||
break;
|
||||
|
||||
// ═══ KITCHEN — Placeholder (needs KDS) ═══
|
||||
// ═══ KITCHEN — KDS Station View ═══
|
||||
case "kitchen":
|
||||
<div class="admin-panel">
|
||||
<div class="admin-panel__body" style="text-align:center;padding:60px 20px;">
|
||||
<div style="width:80px;height:80px;border-radius:24px;background:rgba(249,115,22,0.1);display:flex;align-items:center;justify-content:center;margin:0 auto 20px;">
|
||||
<i data-lucide="flame" style="width:36px;height:36px;color:#F97316;"></i>
|
||||
</div>
|
||||
<h2 style="font-size:22px;font-weight:700;margin:0 0 8px;color:var(--pos-text-primary, #FFFFFF);">Kitchen Display System</h2>
|
||||
<p style="font-size:14px;color:var(--admin-text-tertiary);margin:0 0 12px;max-width:420px;margin-left:auto;margin-right:auto;">Màn hình hiển thị đơn cho bếp (KDS) — tự động nhận đơn từ POS, phân luồng theo trạm bếp.</p>
|
||||
<p style="font-size:13px;color:var(--admin-text-quaternary, #6B6B6F);margin:0;">Tính năng KDS sẽ hoạt động khi kết nối với F&B Engine</p>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;">
|
||||
<div style="display:flex;gap:4px;background:var(--admin-bg-elevated);border-radius:8px;padding:3px;">
|
||||
@foreach (var st in new[] { ("all", "Tất cả"), ("kitchen", "🔥 Bếp"), ("bar", "🍸 Bar"), ("grill", "🥩 Nướng") })
|
||||
{
|
||||
<button @onclick='() => { _kdsStation = st.Item1; StateHasChanged(); }'
|
||||
style="padding:6px 14px;border-radius:6px;border:none;font-size:12px;font-weight:600;cursor:pointer;transition:all 0.2s;@(_kdsStation == st.Item1 ? "background:var(--admin-orange-primary);color:white;" : "background:transparent;color:var(--admin-text-secondary);")">
|
||||
@st.Item2
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;">
|
||||
<span class="admin-status-badge admin-status-badge--setup" style="font-size:11px;"><span class="admin-status-badge__dot"></span>Chờ: 0</span>
|
||||
<span class="admin-status-badge admin-status-badge--paused" style="font-size:11px;"><span class="admin-status-badge__dot"></span>Đang làm: 0</span>
|
||||
<span class="admin-status-badge admin-status-badge--online" style="font-size:11px;"><span class="admin-status-badge__dot"></span>Xong: 0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px;">
|
||||
@foreach (var ticket in new[] {
|
||||
new { Id = "#KDS-001", Table = "Bàn 3", Items = "Phở bò tái (x2), Gỏi cuốn (x1)", Station = "kitchen", Status = "pending", Time = "2 phút" },
|
||||
new { Id = "#KDS-002", Table = "Bàn 7", Items = "Mojito (x3), Bia Tiger (x2)", Station = "bar", Status = "cooking", Time = "5 phút" },
|
||||
new { Id = "#KDS-003", Table = "Bàn 1", Items = "Bò nướng lá lốt (x1)", Station = "grill", Status = "done", Time = "12 phút" }
|
||||
})
|
||||
{
|
||||
if (_kdsStation == "all" || _kdsStation == ticket.Station)
|
||||
{
|
||||
var ticketColor = ticket.Status switch { "pending" => "#F59E0B", "cooking" => "#3B82F6", "done" => "#22C55E", _ => "#6B6B6F" };
|
||||
var ticketLabel = ticket.Status switch { "pending" => "Chờ", "cooking" => "Đang làm", "done" => "Hoàn thành", _ => ticket.Status };
|
||||
<div style="background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);border-top:4px solid @ticketColor;border-radius:12px;padding:16px;">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;">
|
||||
<span style="font-weight:700;font-size:14px;">@ticket.Id</span>
|
||||
<span style="font-size:10px;font-weight:700;padding:3px 10px;border-radius:6px;background:@($"{ticketColor}22");color:@ticketColor;">@ticketLabel</span>
|
||||
</div>
|
||||
<div style="font-size:13px;font-weight:600;margin-bottom:4px;">@ticket.Table</div>
|
||||
<div style="font-size:12px;color:var(--admin-text-tertiary);margin-bottom:12px;line-height:1.5;">@ticket.Items</div>
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;padding-top:8px;border-top:1px solid var(--admin-border-subtle);">
|
||||
<span style="font-size:11px;color:var(--admin-text-tertiary);"><i data-lucide="clock" style="width:12px;height:12px;vertical-align:middle;"></i> @ticket.Time</span>
|
||||
<span style="font-size:11px;color:var(--admin-text-tertiary);">@ticket.Station.ToUpper()</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="admin-panel" style="margin-top:16px;">
|
||||
<div class="admin-panel__body" style="text-align:center;padding:24px;">
|
||||
<p style="font-size:13px;color:var(--admin-text-tertiary);margin:0;"><i data-lucide="info" style="width:14px;height:14px;vertical-align:middle;"></i> Demo KDS — Dữ liệu sẽ real-time khi kết nối F&B Engine</p>
|
||||
</div>
|
||||
</div>
|
||||
break;
|
||||
@@ -717,23 +777,63 @@
|
||||
|
||||
// ═══ TREATMENTS (Beauty — Liệu trình) ═══
|
||||
case "treatments":
|
||||
<div class="admin-panel">
|
||||
<div class="admin-panel__header" style="display:flex;justify-content:space-between;align-items:center;">
|
||||
<h3 class="admin-panel__title">Liệu trình điều trị</h3>
|
||||
</div>
|
||||
<div class="admin-panel__body" style="text-align:center;padding:40px 20px;">
|
||||
<div style="width:64px;height:64px;border-radius:20px;background:rgba(168,85,247,0.1);display:flex;align-items:center;justify-content:center;margin:0 auto 16px;">
|
||||
<i data-lucide="clipboard-list" style="width:28px;height:28px;color:#A855F7;"></i>
|
||||
</div>
|
||||
<h3 style="font-size:18px;font-weight:700;margin:0 0 8px;">Quản lý liệu trình dài hạn</h3>
|
||||
<p style="font-size:14px;color:var(--admin-text-tertiary);margin:0 0 8px;max-width:400px;margin-left:auto;margin-right:auto;">Theo dõi tiến trình điều trị nhiều buổi, ảnh before/after, lịch tái khám sau phẫu thuật.</p>
|
||||
<div style="display:flex;gap:12px;justify-content:center;margin-top:16px;">
|
||||
<span style="display:flex;align-items:center;gap:6px;font-size:12px;color:var(--admin-text-tertiary);"><i data-lucide="camera" style="width:14px;height:14px;"></i> Ảnh Before/After</span>
|
||||
<span style="display:flex;align-items:center;gap:6px;font-size:12px;color:var(--admin-text-tertiary);"><i data-lucide="calendar-check" style="width:14px;height:14px;"></i> Lịch tái khám</span>
|
||||
<span style="display:flex;align-items:center;gap:6px;font-size:12px;color:var(--admin-text-tertiary);"><i data-lucide="file-text" style="width:14px;height:14px;"></i> Hồ sơ y tế</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:4px;background:var(--admin-bg-elevated);border-radius:8px;padding:3px;margin-bottom:16px;">
|
||||
@foreach (var tab in new[] { ("treatment", "📋 Liệu trình"), ("medical", "🏥 Hồ sơ y tế"), ("photos", "📷 Ảnh Before/After") })
|
||||
{
|
||||
<button @onclick='() => { _treatmentTab = tab.Item1; StateHasChanged(); }'
|
||||
style="padding:8px 16px;border-radius:6px;border:none;font-size:12px;font-weight:600;cursor:pointer;transition:all 0.2s;@(_treatmentTab == tab.Item1 ? "background:var(--admin-orange-primary);color:white;" : "background:transparent;color:var(--admin-text-secondary);")">
|
||||
@tab.Item2
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
@if (_treatmentTab == "treatment")
|
||||
{
|
||||
<div class="admin-panel">
|
||||
<div class="admin-panel__header" style="display:flex;justify-content:space-between;align-items:center;">
|
||||
<h3 class="admin-panel__title">Liệu trình điều trị</h3>
|
||||
</div>
|
||||
<div class="admin-panel__body" style="text-align:center;padding:40px 20px;">
|
||||
<div style="width:64px;height:64px;border-radius:20px;background:rgba(168,85,247,0.1);display:flex;align-items:center;justify-content:center;margin:0 auto 16px;">
|
||||
<i data-lucide="clipboard-list" style="width:28px;height:28px;color:#A855F7;"></i>
|
||||
</div>
|
||||
<h3 style="font-size:18px;font-weight:700;margin:0 0 8px;">Quản lý liệu trình dài hạn</h3>
|
||||
<p style="font-size:14px;color:var(--admin-text-tertiary);margin:0;max-width:400px;margin-left:auto;margin-right:auto;">Theo dõi tiến trình điều trị nhiều buổi, lịch tái khám sau phẫu thuật.</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else if (_treatmentTab == "medical")
|
||||
{
|
||||
<div class="admin-panel">
|
||||
<div class="admin-panel__header"><h3 class="admin-panel__title">🏥 Hồ sơ y tế khách hàng</h3></div>
|
||||
<div class="admin-panel__body">
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px;">
|
||||
<div><label style="font-size:12px;font-weight:600;display:block;margin-bottom:4px;">Tìm khách hàng</label><input type="text" placeholder="Nhập tên hoặc SĐT..." style="width:100%;padding:10px 14px;border-radius:8px;background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);font-size:14px;color:var(--admin-text-primary);" /></div>
|
||||
<div><label style="font-size:12px;font-weight:600;display:block;margin-bottom:4px;">Mã hồ sơ</label><div style="padding:10px 14px;border-radius:8px;background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);font-size:14px;color:var(--admin-text-tertiary);">Chưa chọn khách</div></div>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px;">
|
||||
<div><label style="font-size:12px;font-weight:600;display:block;margin-bottom:4px;">🦠 Dị ứng</label><textarea placeholder="Ghi chú dị ứng (thuốc, hóa chất, thực phẩm...)" style="width:100%;padding:10px 14px;border-radius:8px;background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);font-size:13px;color:var(--admin-text-primary);min-height:80px;resize:vertical;"></textarea></div>
|
||||
<div><label style="font-size:12px;font-weight:600;display:block;margin-bottom:4px;">📝 Tiền sử bệnh</label><textarea placeholder="Tiền sử bệnh lý, phẫu thuật, điều trị trước..." style="width:100%;padding:10px 14px;border-radius:8px;background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);font-size:13px;color:var(--admin-text-primary);min-height:80px;resize:vertical;"></textarea></div>
|
||||
</div>
|
||||
<div><label style="font-size:12px;font-weight:600;display:block;margin-bottom:4px;">📅 Lịch tái khám</label><input type="date" style="padding:10px 14px;border-radius:8px;background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);font-size:14px;color:var(--admin-text-primary);" /></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="admin-panel">
|
||||
<div class="admin-panel__header"><h3 class="admin-panel__title">📷 Ảnh Before / After</h3></div>
|
||||
<div class="admin-panel__body" style="text-align:center;padding:40px 20px;">
|
||||
<div style="width:64px;height:64px;border-radius:20px;background:rgba(236,72,153,0.1);display:flex;align-items:center;justify-content:center;margin:0 auto 16px;">
|
||||
<i data-lucide="camera" style="width:28px;height:28px;color:#EC4899;"></i>
|
||||
</div>
|
||||
<h3 style="font-size:18px;font-weight:700;margin:0 0 8px;">So sánh kết quả điều trị</h3>
|
||||
<p style="font-size:14px;color:var(--admin-text-tertiary);margin:0 0 20px;max-width:400px;margin-left:auto;margin-right:auto;">Upload ảnh trước/sau điều trị để theo dõi tiến triển và tư vấn khách hàng.</p>
|
||||
<button style="padding:10px 20px;border-radius:8px;border:2px dashed var(--admin-border-subtle);background:transparent;color:var(--admin-text-tertiary);font-size:13px;cursor:pointer;">
|
||||
<i data-lucide="upload" style="width:16px;height:16px;vertical-align:middle;margin-right:6px;"></i>Chọn ảnh để upload
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
break;
|
||||
|
||||
// ═══ STAFF SCHEDULE (Spa/Beauty — Lịch làm việc) ═══
|
||||
@@ -844,6 +944,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admin-panel" style="margin-top:16px;">
|
||||
<div class="admin-panel__header"><h3 class="admin-panel__title">🧾 Cài đặt hóa đơn / Bill</h3></div>
|
||||
<div class="admin-panel__body">
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px;">
|
||||
<div><label style="font-size:12px;font-weight:600;display:block;margin-bottom:4px;">Header hóa đơn</label><input type="text" value="Cảm ơn quý khách!" style="width:100%;padding:10px 14px;border-radius:8px;background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);font-size:14px;color:var(--admin-text-primary);" /></div>
|
||||
<div><label style="font-size:12px;font-weight:600;display:block;margin-bottom:4px;">Footer hóa đơn</label><input type="text" value="Hẹn gặp lại!" style="width:100%;padding:10px 14px;border-radius:8px;background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);font-size:14px;color:var(--admin-text-primary);" /></div>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;">
|
||||
<div><label style="font-size:12px;font-weight:600;display:block;margin-bottom:4px;">Khổ giấy</label><div style="padding:10px 14px;border-radius:8px;background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);font-size:14px;">80mm</div></div>
|
||||
<div style="display:flex;align-items:center;gap:8px;padding-top:18px;"><input type="checkbox" checked style="accent-color:var(--admin-orange-primary);" /><label style="font-size:13px;">Hiển logo</label></div>
|
||||
<div style="display:flex;align-items:center;gap:8px;padding-top:18px;"><input type="checkbox" style="accent-color:var(--admin-orange-primary);" /><label style="font-size:13px;">In QR Code</label></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
break;
|
||||
|
||||
// ═══ UNKNOWN SECTIONS ═══
|
||||
@@ -918,6 +1032,10 @@
|
||||
private List<PosDataService.LevelDefinitionInfo> _memberLevels = new();
|
||||
private List<PosDataService.ScheduleInfo> _staffSchedules = new();
|
||||
private List<PosDataService.InventoryTxnInfo> _invTxns = new();
|
||||
// P2 state: calendar, KDS, treatments
|
||||
private int _calendarWeekOffset;
|
||||
private string _kdsStation = "all";
|
||||
private string _treatmentTab = "treatment";
|
||||
private List<PosDataService.ResourceInfo> _resources = new();
|
||||
// Customer filter state
|
||||
private string _customerSearch = "";
|
||||
|
||||
Reference in New Issue
Block a user