fix: 修复预约及门店相关问题

This commit is contained in:
MaDaLei 2026-04-17 10:57:31 +08:00
parent 92f1077025
commit 2497204de1
4 changed files with 304 additions and 58 deletions

View File

@ -69,6 +69,10 @@ export const getAppointmentDetail = (id) => get('/appointment/detail', { id })
// 创建预约 // 创建预约
export const createAppointment = (data) => post('/appointment/create', data) export const createAppointment = (data) => post('/appointment/create', data)
/** 门店某日半小时挂号时段(可约 / 已约满 / 已过) */
export const getAppointmentAvailableSlots = (storeId, date) =>
get('/appointment/available-slots', { storeId, date })
// 开始服务 // 开始服务
export const startAppointment = (appointmentId, staffUserId) => export const startAppointment = (appointmentId, staffUserId) =>
post('/appointment/start', { appointmentId, staffUserId }) post('/appointment/start', { appointmentId, staffUserId })
@ -113,6 +117,9 @@ export const updateUser = (data) => put('/user/update', data)
// 门店列表(客户预约选店) // 门店列表(客户预约选店)
export const getStoreList = () => get('/store/list', {}) export const getStoreList = () => get('/store/list', {})
// 门店详情(含预约放号配置)
export const getStoreDetail = (id) => get('/store/get', { id })
// 更新店铺 // 更新店铺
export const updateStore = (data) => put('/store/update', data) export const updateStore = (data) => put('/store/update', data)

View File

@ -66,23 +66,25 @@
<view class="c-field"> <view class="c-field">
<text class="app-form-label">预约时间</text> <text class="app-form-label">预约时间</text>
<view class="c-time-row"> <view class="c-time-row">
<picker mode="date" :value="appointmentDate" @change="onAppointmentDateChange" class="c-time-half"> <picker mode="date" :value="selectedDateStr" @change="onAppointmentDateChange" class="c-time-half">
<view class="app-form-input app-form-picker"> <view class="app-form-input app-form-picker">
<text :class="{ 'app-form-placeholder': !appointmentDate }">{{ appointmentDate || '日期' }}</text> <text :class="{ 'app-form-placeholder': !selectedDateStr }">{{ selectedDateStr || '日期' }}</text>
</view> </view>
</picker> </picker>
<picker <picker
mode="selector" mode="selector"
:range="HALF_HOUR_TIME_SLOTS" :range="availableTimes"
:value="halfHourTimeIndex" :value="slotPickerIndex"
:disabled="!availableTimes.length"
@change="onAppointmentTimeOnlyChange" @change="onAppointmentTimeOnlyChange"
class="c-time-half" class="c-time-half"
> >
<view class="app-form-input app-form-picker"> <view class="app-form-input app-form-picker">
<text :class="{ 'app-form-placeholder': !appointmentTime }">{{ appointmentTime || '时间' }}</text> <text :class="{ 'app-form-placeholder': !appointmentTime && !loadingSlots }">{{ loadingSlots ? '加载中…' : (appointmentTime || '时间') }}</text>
</view> </view>
</picker> </picker>
</view> </view>
<text class="c-store-hint">{{ bookingWindowHint }}</text>
</view> </view>
<view class="c-field"> <view class="c-field">
<text class="app-form-label">备注可选</text> <text class="app-form-label">备注可选</text>
@ -95,16 +97,18 @@
<script setup> <script setup>
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { createAppointment, getServiceTypeList, getPetList, getStoreList, createPet } from '../../api/index.js' import {
createAppointment,
getServiceTypeList,
getPetList,
getStoreList,
createPet,
getAppointmentAvailableSlots
} from '../../api/index.js'
import AppIcon from '../../components/AppIcon.vue' import AppIcon from '../../components/AppIcon.vue'
import { getUserSession, getStoreSession, setStoreSession } from '../../utils/session.js' import { getUserSession, getStoreSession, setStoreSession } from '../../utils/session.js'
import { haversineKm } from '../../utils/geo.js' import { haversineKm } from '../../utils/geo.js'
import { import { normalizeToHalfHour, ymdLocal } from '../../utils/halfHourTime.js'
HALF_HOUR_TIME_SLOTS,
normalizeToHalfHour,
halfHourPickerIndex,
suggestHalfHourForYMD
} from '../../utils/halfHourTime.js'
const userInfo = getUserSession() const userInfo = getUserSession()
const storeInfo = getStoreSession() const storeInfo = getStoreSession()
@ -220,17 +224,24 @@ const initStoresAndLocation = async () => {
applySelectedStoreToSession() applySelectedStoreToSession()
} }
const onStorePickerChange = (e) => { const onStorePickerChange = async (e) => {
selectedStoreIndex.value = Number(e.detail.value) selectedStoreIndex.value = Number(e.detail.value)
applySelectedStoreToSession() applySelectedStoreToSession()
newAppt.value.serviceType = '' newAppt.value.serviceType = ''
loadServiceTypesForSelected() await loadServiceTypesForSelected()
await loadAvailableSlots()
} }
const myPets = ref([]) const myPets = ref([])
const selectedPetId = ref(null) const selectedPetId = ref(null)
const newAppt = ref({ petName: '', petType: '', serviceType: '', appointmentTime: '', remark: '' }) const newAppt = ref({ petName: '', petType: '', serviceType: '', appointmentTime: '', remark: '' })
const creatingAppt = ref(false) const creatingAppt = ref(false)
/** 与日期选择器同步,避免无号源时丢失已选日期 */
const selectedDateStr = ref(ymdLocal())
const availableTimes = ref([])
const loadingSlots = ref(false)
const bookingWindowHint = ref('半小时为一号源,同一时段仅接待一单;已满或已过期不可选')
const normalizeText = (s) => (s || '').toString().trim().toLowerCase() const normalizeText = (s) => (s || '').toString().trim().toLowerCase()
const findMatchedPet = (name, petType) => const findMatchedPet = (name, petType) =>
@ -280,10 +291,6 @@ const onPetTypeChange = (e) => {
} }
} }
const appointmentDate = computed(() => {
const raw = newAppt.value.appointmentTime || ''
return raw.includes('T') ? raw.split('T')[0] : ''
})
const appointmentTime = computed(() => { const appointmentTime = computed(() => {
const raw = newAppt.value.appointmentTime || '' const raw = newAppt.value.appointmentTime || ''
if (!raw.includes('T')) return '' if (!raw.includes('T')) return ''
@ -291,23 +298,80 @@ const appointmentTime = computed(() => {
return normalizeToHalfHour(part) return normalizeToHalfHour(part)
}) })
const halfHourTimeIndex = computed(() => halfHourPickerIndex(appointmentTime.value)) const slotPickerIndex = computed(() => {
const t = appointmentTime.value
const i = availableTimes.value.indexOf(t)
return i >= 0 ? i : 0
})
const loadAvailableSlots = async () => {
const row = orderedStores.value[selectedStoreIndex.value]
const storeId = row?.id
const date = selectedDateStr.value
if (!storeId || !date) {
availableTimes.value = []
return
}
loadingSlots.value = true
try {
const res = await getAppointmentAvailableSlots(storeId, date)
loadingSlots.value = false
if (res.code !== 200 || !res.data?.slots) {
availableTimes.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 a = String(ds).slice(0, 5)
const b = String(le).slice(0, 5)
bookingWindowHint.value = `本店放号 ${a}${b},半小时一号源;同一时段仅一单,已满或已过不可选`
}
availableTimes.value = res.data.slots.filter((s) => s.available).map((s) => s.time)
if (!availableTimes.value.length) {
newAppt.value.appointmentTime = ''
uni.showToast({ title: '当日已无号源,请换一天', icon: 'none' })
return
}
const raw = newAppt.value.appointmentTime || ''
const datePart = raw.includes('T') ? raw.split('T')[0] : ''
const timePart = raw.includes('T')
? normalizeToHalfHour((raw.split('T')[1] || '').slice(0, 5))
: ''
if (datePart === date && timePart && availableTimes.value.includes(timePart)) {
newAppt.value.appointmentTime = `${date}T${timePart}`
} else {
newAppt.value.appointmentTime = `${date}T${availableTimes.value[0]}`
}
} catch (_) {
loadingSlots.value = false
availableTimes.value = []
uni.showToast({ title: '号源加载失败', icon: 'none' })
}
}
const onAppointmentDateChange = (e) => { const onAppointmentDateChange = (e) => {
const date = e?.detail?.value || '' const date = e?.detail?.value || ''
if (!date) { if (!date) {
selectedDateStr.value = ''
newAppt.value.appointmentTime = '' newAppt.value.appointmentTime = ''
availableTimes.value = []
return return
} }
const time = normalizeToHalfHour(suggestHalfHourForYMD(date)) selectedDateStr.value = date
newAppt.value.appointmentTime = `${date}T${time}` loadAvailableSlots()
} }
const onAppointmentTimeOnlyChange = (e) => { const onAppointmentTimeOnlyChange = (e) => {
const idx = Number(e.detail.value) const idx = Number(e.detail.value)
const time = HALF_HOUR_TIME_SLOTS[idx] const time = availableTimes.value[idx]
const date = appointmentDate.value const date = selectedDateStr.value
if (!date) { uni.showToast({ title: '请先选择日期', icon: 'none' }); return } if (!date) {
uni.showToast({ title: '请先选择日期', icon: 'none' })
return
}
if (!time) return
newAppt.value.appointmentTime = `${date}T${time}` newAppt.value.appointmentTime = `${date}T${time}`
} }
@ -376,6 +440,11 @@ const confirmNewAppt = async () => {
if (!a.petType) { uni.showToast({ title: '请选择宠物类型', icon: 'none' }); return } if (!a.petType) { uni.showToast({ title: '请选择宠物类型', icon: 'none' }); return }
if (!a.serviceType) { uni.showToast({ title: '请选择服务类型', icon: 'none' }); return } if (!a.serviceType) { uni.showToast({ title: '请选择服务类型', icon: 'none' }); return }
if (!a.appointmentTime) { uni.showToast({ title: '请选择预约时间', icon: 'none' }); return } if (!a.appointmentTime) { uni.showToast({ title: '请选择预约时间', icon: 'none' }); return }
if (!availableTimes.value.includes(appointmentTime.value)) {
uni.showToast({ title: '该时段不可预约,请重新选择', icon: 'none' })
await loadAvailableSlots()
return
}
const row = orderedStores.value[selectedStoreIndex.value] const row = orderedStores.value[selectedStoreIndex.value]
const storeId = row?.id const storeId = row?.id
if (!storeId) { if (!storeId) {
@ -417,11 +486,13 @@ const loadMyPets = async () => {
} }
onMounted(async () => { onMounted(async () => {
selectedDateStr.value = ymdLocal()
await initStoresAndLocation() await initStoresAndLocation()
if (orderedStores.value.length) { if (orderedStores.value.length) {
await loadServiceTypesForSelected() await loadServiceTypesForSelected()
} }
await loadMyPets() await loadMyPets()
await loadAvailableSlots()
}) })
</script> </script>

View File

@ -107,7 +107,7 @@
<view v-if="filteredOrders.length === 0" class="empty"><text>暂无数据</text></view> <view v-if="filteredOrders.length === 0" class="empty"><text>暂无数据</text></view>
</view> </view>
<view class="fab-appt" @click="showNewAppt = true" hover-class="fab-appt--hover"> <view class="fab-appt" @click="openStaffNewApptDialog" hover-class="fab-appt--hover">
<text class="fab-appt-icon">+</text> <text class="fab-appt-icon">+</text>
</view> </view>
@ -144,23 +144,25 @@
<view class="c-field"> <view class="c-field">
<text class="app-form-label">预约时间</text> <text class="app-form-label">预约时间</text>
<view class="c-time-row"> <view class="c-time-row">
<picker mode="date" :value="appointmentDate" @change="onAppointmentDateChange" class="c-time-half"> <picker mode="date" :value="staffApptDateStr" @change="onStaffApptDateChange" class="c-time-half">
<view class="app-form-input app-form-picker"> <view class="app-form-input app-form-picker">
<text :class="{ 'app-form-placeholder': !appointmentDate }">{{ appointmentDate || '日期' }}</text> <text :class="{ 'app-form-placeholder': !staffApptDateStr }">{{ staffApptDateStr || '日期' }}</text>
</view> </view>
</picker> </picker>
<picker <picker
mode="selector" mode="selector"
:range="HALF_HOUR_TIME_SLOTS" :range="staffAvailableTimes"
:value="halfHourTimeIndex" :value="staffSlotPickerIndex"
@change="onAppointmentTimeOnlyChange" :disabled="!staffAvailableTimes.length"
@change="onStaffApptTimeChange"
class="c-time-half" class="c-time-half"
> >
<view class="app-form-input app-form-picker"> <view class="app-form-input app-form-picker">
<text :class="{ 'app-form-placeholder': !appointmentTime }">{{ appointmentTime || '时间' }}</text> <text :class="{ 'app-form-placeholder': !appointmentTime && !staffLoadingSlots }">{{ staffLoadingSlots ? '加载中…' : (appointmentTime || '时间') }}</text>
</view> </view>
</picker> </picker>
</view> </view>
<text class="c-store-hint home-slot-hint">半小时一号源约满不可选</text>
</view> </view>
<view class="c-field"> <view class="c-field">
<text class="app-form-label">备注可选</text> <text class="app-form-label">备注可选</text>
@ -184,18 +186,20 @@
<script setup> <script setup>
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app' import { onShow } from '@dcloudio/uni-app'
import { getAppointmentList, createAppointment, startAppointment, cancelAppointment, getServiceTypeList } from '../../api/index.js' import {
getAppointmentList,
createAppointment,
startAppointment,
cancelAppointment,
getServiceTypeList,
getAppointmentAvailableSlots
} from '../../api/index.js'
import TabBar from '../../components/TabBar.vue' import TabBar from '../../components/TabBar.vue'
import { getUserSession, getStoreSession } from '../../utils/session.js' import { getUserSession, getStoreSession } from '../../utils/session.js'
import { useNavigator } from '../../composables/useNavigator.js' import { useNavigator } from '../../composables/useNavigator.js'
import { formatDateTimeCN } from '../../utils/datetime.js' import { formatDateTimeCN } from '../../utils/datetime.js'
import { getAppointmentStatusText } from '../../utils/appointment.js' import { getAppointmentStatusText } from '../../utils/appointment.js'
import { import { normalizeToHalfHour, ymdLocal } from '../../utils/halfHourTime.js'
HALF_HOUR_TIME_SLOTS,
normalizeToHalfHour,
halfHourPickerIndex,
suggestHalfHourForYMD
} from '../../utils/halfHourTime.js'
const userInfo = getUserSession() const userInfo = getUserSession()
const storeInfo = getStoreSession() const storeInfo = getStoreSession()
@ -232,10 +236,6 @@ const petTypes = [
] ]
const newAppt = ref({ petName: '', petType: '', serviceType: '', appointmentTime: '', remark: '' }) const newAppt = ref({ petName: '', petType: '', serviceType: '', appointmentTime: '', remark: '' })
const appointmentDate = computed(() => {
const raw = newAppt.value.appointmentTime || ''
return raw.includes('T') ? raw.split('T')[0] : ''
})
const appointmentTime = computed(() => { const appointmentTime = computed(() => {
const raw = newAppt.value.appointmentTime || '' const raw = newAppt.value.appointmentTime || ''
if (!raw.includes('T')) return '' if (!raw.includes('T')) return ''
@ -243,7 +243,16 @@ const appointmentTime = computed(() => {
return normalizeToHalfHour(part) return normalizeToHalfHour(part)
}) })
const halfHourTimeIndex = computed(() => halfHourPickerIndex(appointmentTime.value)) /** B 端弹窗:挂号式时段 */
const staffApptDateStr = ref('')
const staffAvailableTimes = ref([])
const staffLoadingSlots = ref(false)
const staffSlotPickerIndex = computed(() => {
const t = appointmentTime.value
const i = staffAvailableTimes.value.indexOf(t)
return i >= 0 ? i : 0
})
const filteredOrders = computed(() => orders.value.filter(o => { const filteredOrders = computed(() => orders.value.filter(o => {
if (currentStatus.value === 'new') return o.status === 'new' if (currentStatus.value === 'new') return o.status === 'new'
@ -252,21 +261,70 @@ const filteredOrders = computed(() => orders.value.filter(o => {
return true return true
})) }))
const onAppointmentDateChange = (e) => { const loadStaffAvailableSlots = async () => {
const date = e?.detail?.value || '' if (!storeInfo?.id) {
if (!date) { staffAvailableTimes.value = []
newAppt.value.appointmentTime = ''
return return
} }
const time = normalizeToHalfHour(suggestHalfHourForYMD(date)) const date = staffApptDateStr.value || ymdLocal()
newAppt.value.appointmentTime = `${date}T${time}` staffApptDateStr.value = date
staffLoadingSlots.value = true
try {
const res = await getAppointmentAvailableSlots(storeInfo.id, date)
staffLoadingSlots.value = false
if (res.code !== 200 || !res.data?.slots) {
staffAvailableTimes.value = []
return
}
staffAvailableTimes.value = res.data.slots.filter((s) => s.available).map((s) => s.time)
if (!staffAvailableTimes.value.length) {
newAppt.value.appointmentTime = ''
uni.showToast({ title: '当日已无号源', icon: 'none' })
return
}
const raw = newAppt.value.appointmentTime || ''
const datePart = raw.includes('T') ? raw.split('T')[0] : ''
const timePart = raw.includes('T')
? normalizeToHalfHour((raw.split('T')[1] || '').slice(0, 5))
: ''
if (datePart === date && timePart && staffAvailableTimes.value.includes(timePart)) {
newAppt.value.appointmentTime = `${date}T${timePart}`
} else {
newAppt.value.appointmentTime = `${date}T${staffAvailableTimes.value[0]}`
}
} catch (_) {
staffLoadingSlots.value = false
staffAvailableTimes.value = []
}
} }
const onAppointmentTimeOnlyChange = (e) => { const openStaffNewApptDialog = async () => {
showNewAppt.value = true
staffApptDateStr.value = staffApptDateStr.value || ymdLocal()
await loadStaffAvailableSlots()
}
const onStaffApptDateChange = (e) => {
const date = e?.detail?.value || ''
if (!date) {
staffApptDateStr.value = ''
newAppt.value.appointmentTime = ''
staffAvailableTimes.value = []
return
}
staffApptDateStr.value = date
loadStaffAvailableSlots()
}
const onStaffApptTimeChange = (e) => {
const idx = Number(e.detail.value) const idx = Number(e.detail.value)
const time = HALF_HOUR_TIME_SLOTS[idx] const time = staffAvailableTimes.value[idx]
const date = appointmentDate.value const date = staffApptDateStr.value
if (!date) { uni.showToast({ title: '请先选择日期', icon: 'none' }); return } if (!date) {
uni.showToast({ title: '请先选择日期', icon: 'none' })
return
}
if (!time) return
newAppt.value.appointmentTime = `${date}T${time}` newAppt.value.appointmentTime = `${date}T${time}`
} }
@ -362,6 +420,11 @@ const confirmNewAppt = async () => {
if (!a.petType) { uni.showToast({ title: '请选择宠物类型', icon: 'none' }); return } if (!a.petType) { uni.showToast({ title: '请选择宠物类型', icon: 'none' }); return }
if (!a.serviceType) { uni.showToast({ title: '请选择服务类型', icon: 'none' }); return } if (!a.serviceType) { uni.showToast({ title: '请选择服务类型', icon: 'none' }); return }
if (!a.appointmentTime) { uni.showToast({ title: '请选择预约时间', icon: 'none' }); return } if (!a.appointmentTime) { uni.showToast({ title: '请选择预约时间', icon: 'none' }); return }
if (!staffAvailableTimes.value.includes(appointmentTime.value)) {
uni.showToast({ title: '该时段不可预约,请重新选择', icon: 'none' })
await loadStaffAvailableSlots()
return
}
creatingAppt.value = true creatingAppt.value = true
const res = await createAppointment({ ...a, storeId: storeInfo.id, userId: userInfo.id }) const res = await createAppointment({ ...a, storeId: storeInfo.id, userId: userInfo.id })
creatingAppt.value = false creatingAppt.value = false
@ -469,6 +532,13 @@ onShow(() => {
.c-field { margin-bottom: 16px; } .c-field { margin-bottom: 16px; }
.c-field:last-of-type { margin-bottom: 0; } .c-field:last-of-type { margin-bottom: 0; }
.c-store-hint {
display: block;
margin-top: 6px;
font-size: 11px;
color: #999993;
line-height: 1.4;
}
.c-time-row { display: flex; gap: 10px; } .c-time-row { display: flex; gap: 10px; }
.c-time-half { flex: 1; } .c-time-half { flex: 1; }
.home-remark-textarea { min-height: 80px; line-height: 1.5; } .home-remark-textarea { min-height: 80px; line-height: 1.5; }

View File

@ -66,6 +66,37 @@
</div> </div>
</div> </div>
<div class="store-card" style="margin-top: 14px">
<div class="store-card-head">
<span class="store-card-kicker">预约放号</span>
</div>
<div class="store-field">
<div class="store-field-label">
<span class="store-ico"><AppIcon name="pin" :size="15" color="#475569" /></span>
<text>每日首个号源</text>
</div>
<picker mode="selector" :range="HALF_HOUR_TIME_SLOTS" :value="bookingStartIdx" @change="onBookingStartChange">
<view class="app-form-input app-form-picker store-picker-like">
<text>{{ form.bookingDayStart || '请选择' }}</text>
<text class="app-form-arrow"></text>
</view>
</picker>
</div>
<div class="store-field store-field-last">
<div class="store-field-label">
<span class="store-ico"><AppIcon name="pin" :size="15" color="#475569" /></span>
<text>每日最后一个号源</text>
</div>
<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>
<text class="app-form-arrow"></text>
</view>
</picker>
<div class="booking-hint">半小时一档末号须不早于首号保存后对新建预约生效</div>
</div>
</div>
<div class="store-actions"> <div class="store-actions">
<button <button
class="van-button van-button--primary van-button--block store-save-btn" class="van-button van-button--primary van-button--block store-save-btn"
@ -86,7 +117,8 @@
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import AppIcon from '../../components/AppIcon.vue' import AppIcon from '../../components/AppIcon.vue'
import { navigateTo } from '../../utils/globalState.js' import { navigateTo } from '../../utils/globalState.js'
import { updateStore } from '../../api/index.js' import { updateStore, getStoreDetail } from '../../api/index.js'
import { HALF_HOUR_TIME_SLOTS, halfHourPickerIndex } from '../../utils/halfHourTime.js'
import { getStoreSession, setStoreSession } from '../../utils/session.js' import { getStoreSession, setStoreSession } from '../../utils/session.js'
defineEmits(['change-page']) defineEmits(['change-page'])
@ -118,9 +150,33 @@ const form = ref({
address: '', address: '',
intro: '', intro: '',
latitude: null, latitude: null,
longitude: null longitude: null,
bookingDayStart: '09:00',
bookingLastSlotStart: '21:30'
}) })
const toHHmm = (v) => {
if (v == null || v === '') return ''
if (typeof v === 'string') return v.length >= 5 ? v.slice(0, 5) : v
if (Array.isArray(v) && v.length >= 2) {
return `${String(v[0]).padStart(2, '0')}:${String(v[1]).padStart(2, '0')}`
}
return ''
}
const bookingStartIdx = computed(() => halfHourPickerIndex(form.value.bookingDayStart))
const bookingLastIdx = computed(() => halfHourPickerIndex(form.value.bookingLastSlotStart))
const onBookingStartChange = (e) => {
const i = Number(e.detail.value)
form.value.bookingDayStart = HALF_HOUR_TIME_SLOTS[i] || '09:00'
}
const onBookingLastChange = (e) => {
const i = Number(e.detail.value)
form.value.bookingLastSlotStart = HALF_HOUR_TIME_SLOTS[i] || '21:30'
}
const hasMapPin = computed(() => form.value.latitude != null && form.value.longitude != null) const hasMapPin = computed(() => form.value.latitude != null && form.value.longitude != null)
const toCoord = (v) => { const toCoord = (v) => {
@ -151,6 +207,12 @@ const pickAddress = () => {
} }
const saveStore = async () => { const saveStore = async () => {
const i0 = HALF_HOUR_TIME_SLOTS.indexOf(form.value.bookingDayStart)
const i1 = HALF_HOUR_TIME_SLOTS.indexOf(form.value.bookingLastSlotStart)
if (i0 < 0 || i1 < 0 || i1 < i0) {
uni.showToast({ title: '末号须不早于首号', icon: 'none' })
return
}
saving.value = true saving.value = true
const res = await updateStore({ id: storeInfo.id, ...form.value }) const res = await updateStore({ id: storeInfo.id, ...form.value })
saving.value = false saving.value = false
@ -163,15 +225,32 @@ const saveStore = async () => {
} }
} }
onMounted(() => { onMounted(async () => {
form.value = { const base = {
name: storeInfo.name || '', name: storeInfo.name || '',
phone: storeInfo.phone || '', phone: storeInfo.phone || '',
address: storeInfo.address || '', address: storeInfo.address || '',
intro: storeInfo.intro || '', intro: storeInfo.intro || '',
latitude: toCoord(storeInfo.latitude), latitude: toCoord(storeInfo.latitude),
longitude: toCoord(storeInfo.longitude) longitude: toCoord(storeInfo.longitude),
bookingDayStart: toHHmm(storeInfo.bookingDayStart) || '09:00',
bookingLastSlotStart: toHHmm(storeInfo.bookingLastSlotStart) || '21:30'
} }
if (storeInfo.id) {
const res = await getStoreDetail(storeInfo.id)
if (res.code === 200 && res.data) {
const d = res.data
base.bookingDayStart = toHHmm(d.bookingDayStart) || base.bookingDayStart
base.bookingLastSlotStart = toHHmm(d.bookingLastSlotStart) || base.bookingLastSlotStart
if (d.name != null) base.name = d.name
if (d.phone != null) base.phone = d.phone
if (d.address != null) base.address = d.address
if (d.intro != null) base.intro = d.intro
if (d.latitude != null) base.latitude = toCoord(d.latitude)
if (d.longitude != null) base.longitude = toCoord(d.longitude)
}
}
form.value = base
}) })
</script> </script>
@ -361,4 +440,23 @@ onMounted(() => {
font-size: 12px; font-size: 12px;
color: #cbd5e1; color: #cbd5e1;
} }
.store-picker-like {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 44px;
padding: 0 12px;
border-radius: 12px;
background: #f8fafc;
border: 1px solid #e2e8f0;
font-size: 15px;
color: #111827;
}
.booking-hint {
margin-top: 8px;
font-size: 12px;
color: #94a3b8;
line-height: 1.45;
}
</style> </style>