feat: book against service duration
This commit is contained in:
parent
9a12ee07b0
commit
d29ece3a85
@ -86,9 +86,9 @@ export const getAppointmentDetail = (id) => get('/appointment/detail', { id })
|
||||
// 创建预约:登录人身份始终由后端派生;customer 传选中门店,门店代客预约传 customerUserId 或 customerPhone
|
||||
export const createAppointment = (data) => post('/appointment/create', data)
|
||||
|
||||
/** 门店某日可预约半小时档(可约 / 已满 / 已过);公开接口 */
|
||||
export const getAppointmentAvailableSlots = (storeId, date) =>
|
||||
get('/appointment/available-slots', { storeId, date })
|
||||
/** 门店某日可预约开始时段;按服务时长与门店容量计算,公开接口。 */
|
||||
export const getAppointmentAvailableSlots = (storeId, date, serviceType) =>
|
||||
get('/appointment/available-slots', { storeId, date, serviceType })
|
||||
|
||||
// 开始服务(staffUserId 由后端从上下文派生;保留旧签名兼容,不传 staffUserId)
|
||||
export const startAppointment = (appointmentId/*, staffUserId */) =>
|
||||
@ -147,8 +147,9 @@ export const getServiceTypeList = (storeId) => {
|
||||
return get('/service-type/list', params)
|
||||
}
|
||||
|
||||
// 创建服务类型
|
||||
export const createServiceType = (storeId, name) => post('/service-type/create', { storeId, name })
|
||||
// 创建服务类型(storeId 仅保留旧签名兼容,后端从登录态派生)
|
||||
export const createServiceType = (storeId, name, durationMinutes) =>
|
||||
post('/service-type/create', { storeId, name, durationMinutes })
|
||||
|
||||
// 删除服务类型
|
||||
export const deleteServiceType = (id) => del(`/service-type/delete?id=${id}`)
|
||||
|
||||
@ -38,6 +38,10 @@
|
||||
<text class="label">预约时间</text>
|
||||
<text class="value time">{{ timeDisplay }}</text>
|
||||
</view>
|
||||
<view v-if="detail.endTime" class="detail-row">
|
||||
<text class="label">预计结束</text>
|
||||
<text class="value time">{{ endTimeDisplay }}(约 {{ detail.durationMinutes || 60 }} 分钟)</text>
|
||||
</view>
|
||||
<view v-if="detail.remark" class="detail-row block">
|
||||
<text class="label">备注</text>
|
||||
<text class="value remark">{{ detail.remark }}</text>
|
||||
@ -84,6 +88,7 @@ const navSafeStyle = (() => {
|
||||
const statusText = computed(() => (detail.value ? getAppointmentStatusText(detail.value.status) : ''))
|
||||
|
||||
const timeDisplay = computed(() => formatDateTimeCN(detail.value?.appointmentTime))
|
||||
const endTimeDisplay = computed(() => formatDateTimeCN(detail.value?.endTime))
|
||||
|
||||
const tagClass = (status) => getAppointmentTagClass(status)
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@
|
||||
</view>
|
||||
<view class="c-field">
|
||||
<text class="app-form-label">服务类型</text>
|
||||
<picker mode="selector" :range="serviceTypes" range-key="label" @change="e => newAppt.serviceType = serviceTypes[e.detail.value].value">
|
||||
<picker mode="selector" :range="serviceTypes" range-key="label" @change="onServiceTypeChange">
|
||||
<view class="app-form-input app-form-picker">
|
||||
<text :class="{ 'app-form-placeholder': !newAppt.serviceType }">{{ newAppt.serviceType || '请选择' }}</text>
|
||||
<text class="app-form-arrow">›</text>
|
||||
@ -330,8 +330,9 @@ const creatingAppt = ref(false)
|
||||
/** 与日期选择器同步,避免无号源时丢失已选日期 */
|
||||
const selectedDateStr = ref(ymdLocal())
|
||||
const availableTimes = ref([])
|
||||
const availableSlotEnds = ref({})
|
||||
const loadingSlots = ref(false)
|
||||
const bookingWindowHint = ref('请选择半小时时间段;同一时段仅接待一单,已满或已过期不可选')
|
||||
const bookingWindowHint = ref('请选择服务后查看可预约开始时间;系统会按服务时长校验完整容量')
|
||||
|
||||
const normalizeText = (s) => (s || '').toString().trim().toLowerCase()
|
||||
|
||||
@ -397,11 +398,13 @@ const slotPickerIndex = computed(() => {
|
||||
|
||||
/** 滚轮选项展示为「09:00–09:30」 */
|
||||
const availableSlotLabels = computed(() =>
|
||||
availableTimes.value.map((t) => formatHalfHourSlotRange(t))
|
||||
availableTimes.value.map((t) => `${t}–${availableSlotEnds.value[t] || formatHalfHourSlotRange(t).slice(6)}`)
|
||||
)
|
||||
|
||||
const selectedSlotRangeLabel = computed(() =>
|
||||
appointmentTime.value ? formatHalfHourSlotRange(appointmentTime.value) : ''
|
||||
appointmentTime.value
|
||||
? `${appointmentTime.value}–${availableSlotEnds.value[appointmentTime.value] || formatHalfHourSlotRange(appointmentTime.value).slice(6)}`
|
||||
: ''
|
||||
)
|
||||
|
||||
const showTryTomorrow = computed(
|
||||
@ -433,20 +436,24 @@ const loadAvailableSlots = async () => {
|
||||
}
|
||||
loadingSlots.value = true
|
||||
try {
|
||||
const res = await getAppointmentAvailableSlots(storeId, date)
|
||||
const res = await getAppointmentAvailableSlots(storeId, date, newAppt.value.serviceType || undefined)
|
||||
loadingSlots.value = false
|
||||
if (res.code !== 200 || !res.data?.slots) {
|
||||
availableTimes.value = []
|
||||
availableSlotEnds.value = {}
|
||||
uni.showToast({ title: res.message || '号源加载失败', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const ds = res.data.dayStart
|
||||
const le = res.data.lastSlotStart
|
||||
if (ds != null && le != null) {
|
||||
const closing = res.data.closingTime
|
||||
if (ds != null && closing != null) {
|
||||
const a = String(ds).slice(0, 5)
|
||||
const b = String(le).slice(0, 5)
|
||||
bookingWindowHint.value = `本店可约 ${a}~${b};以下为半小时时段,同一时段仅一单,已满或已过不可选`
|
||||
const b = String(closing).slice(0, 5)
|
||||
const mins = Number(res.data.durationMinutes || 60)
|
||||
const capacity = Number(res.data.bookingCapacity || 1)
|
||||
bookingWindowHint.value = `营业容量 ${a}~${b};本服务约 ${mins} 分钟,门店并发接待 ${capacity} 位`
|
||||
}
|
||||
availableSlotEnds.value = Object.fromEntries(res.data.slots.map((s) => [s.time, s.endTime]))
|
||||
availableTimes.value = res.data.slots.filter((s) => s.available).map((s) => s.time)
|
||||
if (!availableTimes.value.length) {
|
||||
newAppt.value.appointmentTime = ''
|
||||
@ -466,6 +473,7 @@ const loadAvailableSlots = async () => {
|
||||
} catch (_) {
|
||||
loadingSlots.value = false
|
||||
availableTimes.value = []
|
||||
availableSlotEnds.value = {}
|
||||
uni.showToast({ title: '号源加载失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
@ -494,12 +502,25 @@ const onAppointmentTimeOnlyChange = (e) => {
|
||||
newAppt.value.appointmentTime = `${date}T${time}`
|
||||
}
|
||||
|
||||
const onServiceTypeChange = (e) => {
|
||||
const selected = serviceTypes.value[Number(e.detail.value)]
|
||||
newAppt.value.serviceType = selected?.value || ''
|
||||
loadAvailableSlots()
|
||||
}
|
||||
|
||||
const loadServiceTypesForSelected = async () => {
|
||||
const row = orderedStores.value[selectedStoreIndex.value]
|
||||
const sid = row?.id
|
||||
const res = await getServiceTypeList(sid ?? undefined)
|
||||
if (res.code === 200 && Array.isArray(res.data)) {
|
||||
serviceTypes.value = res.data.map((s) => ({ label: s.name, value: s.name }))
|
||||
serviceTypes.value = res.data.map((s) => ({
|
||||
label: `${s.name} · 约${Number(s.durationMinutes || 60)}分钟`,
|
||||
value: s.name,
|
||||
durationMinutes: Number(s.durationMinutes || 60)
|
||||
}))
|
||||
if (newAppt.value.serviceType && !serviceTypes.value.some((s) => s.value === newAppt.value.serviceType)) {
|
||||
newAppt.value.serviceType = ''
|
||||
}
|
||||
if (sid) {
|
||||
try {
|
||||
const last = uni.getStorageSync(lastServiceStorageKey(sid))
|
||||
|
||||
@ -228,7 +228,7 @@
|
||||
</view>
|
||||
<view class="c-field">
|
||||
<text class="app-form-label">服务类型</text>
|
||||
<picker mode="selector" :range="serviceTypes" range-key="label" @change="e => newAppt.serviceType = serviceTypes[e.detail.value].value">
|
||||
<picker mode="selector" :range="serviceTypes" range-key="label" @change="onStaffServiceTypeChange">
|
||||
<view class="app-form-input app-form-picker">
|
||||
<text :class="{ 'app-form-placeholder': !newAppt.serviceType }">{{ newAppt.serviceType || '请选择' }}</text>
|
||||
<text class="app-form-arrow">›</text>
|
||||
@ -256,7 +256,7 @@
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<text class="c-store-hint home-slot-hint">每行半小时时段,约满不可选</text>
|
||||
<text class="c-store-hint home-slot-hint">按服务时长与门店并发容量计算,约满不可选</text>
|
||||
</view>
|
||||
<view class="c-field">
|
||||
<text class="app-form-label">备注(可选)</text>
|
||||
@ -421,6 +421,7 @@ const appointmentTime = computed(() => {
|
||||
/** B 端弹窗:按半小时档选可约时段 */
|
||||
const staffApptDateStr = ref('')
|
||||
const staffAvailableTimes = ref([])
|
||||
const staffAvailableSlotEnds = ref({})
|
||||
const staffLoadingSlots = ref(false)
|
||||
|
||||
const staffSlotPickerIndex = computed(() => {
|
||||
@ -430,11 +431,13 @@ const staffSlotPickerIndex = computed(() => {
|
||||
})
|
||||
|
||||
const staffAvailableSlotLabels = computed(() =>
|
||||
staffAvailableTimes.value.map((t) => formatHalfHourSlotRange(t))
|
||||
staffAvailableTimes.value.map((t) => `${t}–${staffAvailableSlotEnds.value[t] || formatHalfHourSlotRange(t).slice(6)}`)
|
||||
)
|
||||
|
||||
const staffSelectedSlotRangeLabel = computed(() =>
|
||||
appointmentTime.value ? formatHalfHourSlotRange(appointmentTime.value) : ''
|
||||
appointmentTime.value
|
||||
? `${appointmentTime.value}–${staffAvailableSlotEnds.value[appointmentTime.value] || formatHalfHourSlotRange(appointmentTime.value).slice(6)}`
|
||||
: ''
|
||||
)
|
||||
|
||||
const filteredOrders = computed(() => orders.value.filter(o => {
|
||||
@ -525,12 +528,14 @@ const loadStaffAvailableSlots = async () => {
|
||||
staffApptDateStr.value = date
|
||||
staffLoadingSlots.value = true
|
||||
try {
|
||||
const res = await getAppointmentAvailableSlots(storeInfo.id, date)
|
||||
const res = await getAppointmentAvailableSlots(storeInfo.id, date, newAppt.value.serviceType || undefined)
|
||||
staffLoadingSlots.value = false
|
||||
if (res.code !== 200 || !res.data?.slots) {
|
||||
staffAvailableTimes.value = []
|
||||
staffAvailableSlotEnds.value = {}
|
||||
return
|
||||
}
|
||||
staffAvailableSlotEnds.value = Object.fromEntries(res.data.slots.map((s) => [s.time, s.endTime]))
|
||||
staffAvailableTimes.value = res.data.slots.filter((s) => s.available).map((s) => s.time)
|
||||
if (!staffAvailableTimes.value.length) {
|
||||
newAppt.value.appointmentTime = ''
|
||||
@ -550,6 +555,7 @@ const loadStaffAvailableSlots = async () => {
|
||||
} catch (_) {
|
||||
staffLoadingSlots.value = false
|
||||
staffAvailableTimes.value = []
|
||||
staffAvailableSlotEnds.value = {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -559,6 +565,12 @@ const openStaffNewApptDialog = async () => {
|
||||
await loadStaffAvailableSlots()
|
||||
}
|
||||
|
||||
const onStaffServiceTypeChange = (e) => {
|
||||
const selected = serviceTypes.value[Number(e.detail.value)]
|
||||
newAppt.value.serviceType = selected?.value || ''
|
||||
loadStaffAvailableSlots()
|
||||
}
|
||||
|
||||
const onStaffApptDateChange = (e) => {
|
||||
const date = e?.detail?.value || ''
|
||||
if (!date) {
|
||||
@ -654,7 +666,11 @@ const loadServiceTypes = async () => {
|
||||
if (!storeInfo.id) return
|
||||
const res = await getServiceTypeList(storeInfo.id)
|
||||
if (res.code === 200) {
|
||||
serviceTypes.value = res.data.map(s => ({ label: s.name, value: s.name }))
|
||||
serviceTypes.value = res.data.map(s => ({
|
||||
label: `${s.name} · 约${Number(s.durationMinutes || 60)}分钟`,
|
||||
value: s.name,
|
||||
durationMinutes: Number(s.durationMinutes || 60)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
</view>
|
||||
<view class="sched-hero-text">
|
||||
<text class="sched-hero-title">时段一览</text>
|
||||
<text class="sched-hero-desc">绿色为客户预约;橙色为到店占用;灰色为暂停线上预约。点空白格可手动占用,点占用可取消。</text>
|
||||
<text class="sched-hero-desc">绿色为客户预约;橙色为到店占用;灰色为暂停线上预约。每行显示已用/总容量。</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
<view class="sched-main">
|
||||
<template v-if="row.kind === 'appointment' && row.appointment">
|
||||
<text class="sched-line-title">{{ row.appointment.petName || '宠物' }} · {{ row.appointment.serviceType || '服务' }}</text>
|
||||
<text class="sched-line-sub">{{ apptStatusText(row.appointment.status) }}</text>
|
||||
<text class="sched-line-sub">{{ apptStatusText(row.appointment.status) }} · 容量 {{ row.usedCapacity || 0 }}/{{ row.totalCapacity || 1 }}</text>
|
||||
</template>
|
||||
<template v-else-if="row.kind === 'block' && row.block">
|
||||
<text class="sched-line-title">{{ blockTitle(row.block) }}</text>
|
||||
@ -61,7 +61,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="sched-foot-hint">与「营业时间」一致,每半小时一档;占用后客户端该档不可再约。</view>
|
||||
<view class="sched-foot-hint">与营业容量时段一致;服务和到店占用会跨半小时桶消耗名额,暂停预约会关闭全部名额。</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@ -212,6 +212,7 @@ function onRowTap(row) {
|
||||
const res = await createScheduleBlock({
|
||||
storeId: storeInfo.id,
|
||||
slotStart,
|
||||
durationMinutes: 30,
|
||||
blockType,
|
||||
note: '',
|
||||
createdByUserId: userInfo.id
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
<view class="st-name-row">
|
||||
<span class="st-dot"><AppIcon name="service" :size="14" /></span>
|
||||
<text class="st-name">{{ s.name }}</text>
|
||||
<text class="st-duration">约 {{ s.durationMinutes || 60 }} 分钟</text>
|
||||
<view v-if="!s.storeId" class="van-tag van-tag--success van-tag--small system-tag">系统默认</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -58,6 +59,13 @@
|
||||
<view class="popup-desc">建议使用简洁明确的命名,方便前台下单与报告展示。</view>
|
||||
<view class="field-label">服务类型名称</view>
|
||||
<input v-model="newName" class="van-field" placeholder="请输入" />
|
||||
<view class="field-label st-duration-label">预计服务时长</view>
|
||||
<picker mode="selector" :range="DURATION_LABELS" :value="durationPickerIndex" @change="onDurationChange">
|
||||
<view class="app-form-input app-form-picker">
|
||||
<text>{{ newDuration }} 分钟</text>
|
||||
<text class="app-form-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="popup-footer">
|
||||
<view class="popup-actions">
|
||||
@ -71,7 +79,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import AppIcon from '../../components/AppIcon.vue'
|
||||
import { navigateTo } from '../../utils/globalState.js'
|
||||
import { getServiceTypeList, createServiceType, deleteServiceType } from '../../api/index.js'
|
||||
@ -102,6 +110,10 @@ const navSafeStyle = (() => {
|
||||
const serviceTypes = ref([])
|
||||
const showNew = ref(false)
|
||||
const newName = ref('')
|
||||
const DURATION_OPTIONS = Array.from({ length: 16 }, (_, i) => (i + 1) * 30)
|
||||
const DURATION_LABELS = DURATION_OPTIONS.map((minutes) => `${minutes} 分钟`)
|
||||
const newDuration = ref(60)
|
||||
const durationPickerIndex = computed(() => Math.max(0, DURATION_OPTIONS.indexOf(newDuration.value)))
|
||||
const swipedId = ref(null)
|
||||
const touchStartX = ref(0)
|
||||
const touchCurrentX = ref(0)
|
||||
@ -111,12 +123,17 @@ const load = async () => {
|
||||
if (res.code === 200) serviceTypes.value = res.data
|
||||
}
|
||||
|
||||
const onDurationChange = (e) => {
|
||||
newDuration.value = DURATION_OPTIONS[Number(e.detail.value)] || 60
|
||||
}
|
||||
|
||||
const confirmAdd = async () => {
|
||||
if (!newName.value) { uni.showToast({ title: '请输入服务类型名称', icon: 'none' }); return }
|
||||
const res = await createServiceType(storeInfo.id, newName.value)
|
||||
const res = await createServiceType(storeInfo.id, newName.value, newDuration.value)
|
||||
if (res.code === 200) {
|
||||
uni.showToast({ title: '添加成功', icon: 'success' })
|
||||
newName.value = ''
|
||||
newDuration.value = 60
|
||||
showNew.value = false
|
||||
load()
|
||||
} else {
|
||||
@ -193,6 +210,8 @@ onMounted(() => load())
|
||||
background: var(--c-slate-100);
|
||||
}
|
||||
.st-name { font-size: 15px; font-weight: 600; color: var(--c-gray-800); }
|
||||
.st-duration { margin-left: auto; font-size: 12px; color: var(--c-slate-500); }
|
||||
.st-duration-label { margin-top: 14px; }
|
||||
.system-tag { margin-left: 8px; }
|
||||
/* 与员工管理页一致:删除区绝对贴底,主内容盖住;左滑才露出 */
|
||||
.st-swipe-wrap {
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
</view>
|
||||
<view class="store-hero-text">
|
||||
<text class="store-hero-title">门店资料</text>
|
||||
<text class="store-hero-desc">在此维护门店名称、电话、地址与简介,并设置「营业时间」。营业时间决定客户线上可预约的时段范围(每半小时为一个时段,同一时段仅一单)。</text>
|
||||
<text class="store-hero-desc">在此维护门店资料、营业容量时段与并发接待数。系统会按服务时长检查每个半小时容量桶。</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -68,7 +68,7 @@
|
||||
<view class="store-card store-card--hours store-card--after-basic">
|
||||
<view class="store-card-head">
|
||||
<text class="store-card-title">营业时间</text>
|
||||
<text class="store-card-sub">客户可预约时段为「开始」至「结束」之间的半点档;每半小时为一档,每档最多一单,已满或已过不可选。</text>
|
||||
<text class="store-card-sub">服务必须在开始至结束之间完成;线上预约和到店占用共同消耗并发名额。</text>
|
||||
</view>
|
||||
<view class="store-field">
|
||||
<view class="store-field-label">
|
||||
@ -83,12 +83,12 @@
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="store-field store-field-last">
|
||||
<view class="store-field">
|
||||
<view class="store-field-label">
|
||||
<span class="store-ico"><AppIcon name="service" :size="15" :color="SLATE_600" /></span>
|
||||
<text>结束时间</text>
|
||||
</view>
|
||||
<text class="store-field-tip">当日最后一个可预约的半点起始时刻(例如 21:30 表示最晚可约 21:00–21:30 这一档)</text>
|
||||
<text class="store-field-tip">最后一个容量桶的开始时刻(例如 21:30 表示营业容量至 22:00)</text>
|
||||
<picker mode="selector" :range="HALF_HOUR_TIME_SLOTS" :value="bookingLastIdx" @change="onBookingLastChange">
|
||||
<view class="app-form-input app-form-picker store-picker-like">
|
||||
<text>{{ form.bookingLastSlotStart || '请选择' }}</text>
|
||||
@ -97,6 +97,19 @@
|
||||
</picker>
|
||||
<view class="booking-hint">结束须不早于开始。保存后对新建预约生效。</view>
|
||||
</view>
|
||||
<view class="store-field store-field-last">
|
||||
<view class="store-field-label">
|
||||
<span class="store-ico"><AppIcon name="profile" :size="15" :color="SLATE_600" /></span>
|
||||
<text>并发接待数</text>
|
||||
</view>
|
||||
<text class="store-field-tip">同一半小时最多可同时服务的顾客数</text>
|
||||
<picker mode="selector" :range="CAPACITY_OPTIONS" :value="bookingCapacityIdx" @change="onBookingCapacityChange">
|
||||
<view class="app-form-input app-form-picker store-picker-like">
|
||||
<text>{{ form.bookingCapacity }} 位</text>
|
||||
<text class="app-form-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="store-actions">
|
||||
@ -147,6 +160,7 @@ const navSafeStyle = (() => {
|
||||
})()
|
||||
const saving = ref(false)
|
||||
const pickingLocation = ref(false)
|
||||
const CAPACITY_OPTIONS = Array.from({ length: 10 }, (_, i) => i + 1)
|
||||
const form = ref({
|
||||
name: '',
|
||||
phone: '',
|
||||
@ -155,7 +169,8 @@ const form = ref({
|
||||
latitude: null,
|
||||
longitude: null,
|
||||
bookingDayStart: '09:00',
|
||||
bookingLastSlotStart: '21:30'
|
||||
bookingLastSlotStart: '21:30',
|
||||
bookingCapacity: 1
|
||||
})
|
||||
|
||||
const toHHmm = (v) => {
|
||||
@ -169,6 +184,7 @@ const toHHmm = (v) => {
|
||||
|
||||
const bookingStartIdx = computed(() => halfHourPickerIndex(form.value.bookingDayStart))
|
||||
const bookingLastIdx = computed(() => halfHourPickerIndex(form.value.bookingLastSlotStart))
|
||||
const bookingCapacityIdx = computed(() => Math.max(0, CAPACITY_OPTIONS.indexOf(Number(form.value.bookingCapacity || 1))))
|
||||
|
||||
const onBookingStartChange = (e) => {
|
||||
const i = Number(e.detail.value)
|
||||
@ -180,6 +196,10 @@ const onBookingLastChange = (e) => {
|
||||
form.value.bookingLastSlotStart = HALF_HOUR_TIME_SLOTS[i] || '21:30'
|
||||
}
|
||||
|
||||
const onBookingCapacityChange = (e) => {
|
||||
form.value.bookingCapacity = CAPACITY_OPTIONS[Number(e.detail.value)] || 1
|
||||
}
|
||||
|
||||
const hasMapPin = computed(() => form.value.latitude != null && form.value.longitude != null)
|
||||
|
||||
const toCoord = (v) => {
|
||||
@ -237,7 +257,8 @@ onMounted(async () => {
|
||||
latitude: toCoord(storeInfo.latitude),
|
||||
longitude: toCoord(storeInfo.longitude),
|
||||
bookingDayStart: toHHmm(storeInfo.bookingDayStart) || '09:00',
|
||||
bookingLastSlotStart: toHHmm(storeInfo.bookingLastSlotStart) || '21:30'
|
||||
bookingLastSlotStart: toHHmm(storeInfo.bookingLastSlotStart) || '21:30',
|
||||
bookingCapacity: Number(storeInfo.bookingCapacity || 1)
|
||||
}
|
||||
if (storeInfo.id) {
|
||||
const res = await getStoreDetail(storeInfo.id)
|
||||
@ -245,6 +266,7 @@ onMounted(async () => {
|
||||
const d = res.data
|
||||
base.bookingDayStart = toHHmm(d.bookingDayStart) || base.bookingDayStart
|
||||
base.bookingLastSlotStart = toHHmm(d.bookingLastSlotStart) || base.bookingLastSlotStart
|
||||
base.bookingCapacity = Number(d.bookingCapacity || base.bookingCapacity)
|
||||
if (d.name != null) base.name = d.name
|
||||
if (d.phone != null) base.phone = d.phone
|
||||
if (d.address != null) base.address = d.address
|
||||
|
||||
Loading…
Reference in New Issue
Block a user