-
{{ business.title }}
+
+
+
+
{{ business.title }}
+
+
+
+
+
{{ formattedRating }}
+
({{ reviewCount }})
+
+
+
+
diff --git a/src/components/home/HomeBusinessCard.vue b/src/components/home/HomeBusinessCard.vue
index 8b3da26..93c25a4 100644
--- a/src/components/home/HomeBusinessCard.vue
+++ b/src/components/home/HomeBusinessCard.vue
@@ -19,6 +19,12 @@
{{ business.title }}
+
+
@@ -138,6 +140,7 @@ import { useRouter } from 'vue-router';
import {
cancelBooking,
confirmBooking,
+ completeBooking,
fetchBookings,
initiateBookingPayment,
} from '@/api/bookings';
@@ -277,6 +280,31 @@ async function onConfirm(entry: Booking[]) {
}
}
+function canComplete(booking: Booking) {
+ return auth.isBusinessOwner && booking.status === 'confirmed';
+}
+
+function canCompleteEntry(entry: Booking[]) {
+ return entry.some((booking) => canComplete(booking));
+}
+
+async function onComplete(entry: Booking[]) {
+ const completable = entry.filter((booking) => canComplete(booking));
+ if (!completable.length) return;
+
+ actingKey.value = entry[0]?.bookingGroupId ?? entry[0]?.id ?? null;
+ try {
+ const updated = await Promise.all(
+ completable.map((booking) => completeBooking(booking.id)),
+ );
+ applyUpdatedBookings(updated);
+ } catch (e) {
+ error.value = e instanceof ApiError ? e.message : 'ثبت انجام خدمت ناموفق بود.';
+ } finally {
+ actingKey.value = null;
+ }
+}
+
async function onPay(entry: Booking[]) {
const payable = entry.find((booking) => canPay(booking));
if (!payable) return;
diff --git a/src/views/app/AppOwnerView.vue b/src/views/app/AppOwnerView.vue
index e60f4cb..5ad6a0d 100644
--- a/src/views/app/AppOwnerView.vue
+++ b/src/views/app/AppOwnerView.vue
@@ -163,6 +163,21 @@
+
+
ذخیره تنظیمات نوبتدهی
@@ -543,6 +558,7 @@ const bookingForm = ref({
concurrentCapacity: '1',
slotStepMinutes: '30',
autoApproveBookings: false,
+ tipsEnabled: false,
});
const bookingExpanded = ref(false);
@@ -590,7 +606,8 @@ const servicesSummary = computed(() => {
const bookingSummary = computed(() => {
const auto = bookingForm.value.autoApproveBookings ? 'تأیید خودکار' : 'تأیید دستی';
- return `${bookingForm.value.concurrentCapacity} همزمان · گام ${bookingForm.value.slotStepMinutes} دقیقه · ${auto}`;
+ const tips = bookingForm.value.tipsEnabled ? 'حسن انجام کار فعال' : 'بدون حسن انجام کار';
+ return `${bookingForm.value.concurrentCapacity} همزمان · گام ${bookingForm.value.slotStepMinutes} دقیقه · ${auto} · ${tips}`;
});
function emptyClassPriceForm() {
@@ -690,6 +707,7 @@ onMounted(async () => {
concurrentCapacity: String(business.value.concurrentCapacity ?? 1),
slotStepMinutes: String(business.value.slotStepMinutes ?? 30),
autoApproveBookings: business.value.autoApproveBookings === true,
+ tipsEnabled: business.value.tipsEnabled === true,
};
await loadServicesAndTemplates();
}
@@ -813,6 +831,7 @@ async function onSaveBookingSettings() {
concurrentCapacity,
slotStepMinutes,
autoApproveBookings: bookingForm.value.autoApproveBookings,
+ tipsEnabled: bookingForm.value.tipsEnabled,
});
tenant.syncSingleBusiness(business.value);
bookingMessage.value = 'تنظیمات نوبتدهی ذخیره شد.';