fix: 修复预约及门店相关问题
This commit is contained in:
parent
92f1077025
commit
2497204de1
@ -69,6 +69,10 @@ export const getAppointmentDetail = (id) => get('/appointment/detail', { id })
|
||||
// 创建预约
|
||||
export const createAppointment = (data) => post('/appointment/create', data)
|
||||
|
||||
/** 门店某日半小时挂号时段(可约 / 已约满 / 已过) */
|
||||
export const getAppointmentAvailableSlots = (storeId, date) =>
|
||||
get('/appointment/available-slots', { storeId, date })
|
||||
|
||||
// 开始服务
|
||||
export const startAppointment = (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 getStoreDetail = (id) => get('/store/get', { id })
|
||||
|
||||
// 更新店铺
|
||||
export const updateStore = (data) => put('/store/update', data)
|
||||
|
||||
|
||||
@ -66,23 +66,25 @@
|
||||
<view class="c-field">
|
||||
<text class="app-form-label">预约时间</text>
|
||||
<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">
|
||||
<text :class="{ 'app-form-placeholder': !appointmentDate }">{{ appointmentDate || '日期' }}</text>
|
||||
<text :class="{ 'app-form-placeholder': !selectedDateStr }">{{ selectedDateStr || '日期' }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<picker
|
||||
mode="selector"
|
||||
:range="HALF_HOUR_TIME_SLOTS"
|
||||
:value="halfHourTimeIndex"
|
||||
:range="availableTimes"
|
||||
:value="slotPickerIndex"
|
||||
:disabled="!availableTimes.length"
|
||||
@change="onAppointmentTimeOnlyChange"
|
||||
class="c-time-half"
|
||||
>
|
||||
<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>
|
||||
</picker>
|
||||
</view>
|
||||
<text class="c-store-hint">{{ bookingWindowHint }}</text>
|
||||
</view>
|
||||
<view class="c-field">
|
||||
<text class="app-form-label">备注(可选)</text>
|
||||
@ -95,16 +97,18 @@
|
||||
|
||||
<script setup>
|
||||
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 { getUserSession, getStoreSession, setStoreSession } from '../../utils/session.js'
|
||||
import { haversineKm } from '../../utils/geo.js'
|
||||
import {
|
||||
HALF_HOUR_TIME_SLOTS,
|
||||
normalizeToHalfHour,
|
||||
halfHourPickerIndex,
|
||||
suggestHalfHourForYMD
|
||||
} from '../../utils/halfHourTime.js'
|
||||
import { normalizeToHalfHour, ymdLocal } from '../../utils/halfHourTime.js'
|
||||
|
||||
const userInfo = getUserSession()
|
||||
const storeInfo = getStoreSession()
|
||||
@ -220,17 +224,24 @@ const initStoresAndLocation = async () => {
|
||||
applySelectedStoreToSession()
|
||||
}
|
||||
|
||||
const onStorePickerChange = (e) => {
|
||||
const onStorePickerChange = async (e) => {
|
||||
selectedStoreIndex.value = Number(e.detail.value)
|
||||
applySelectedStoreToSession()
|
||||
newAppt.value.serviceType = ''
|
||||
loadServiceTypesForSelected()
|
||||
await loadServiceTypesForSelected()
|
||||
await loadAvailableSlots()
|
||||
}
|
||||
const myPets = ref([])
|
||||
const selectedPetId = ref(null)
|
||||
const newAppt = ref({ petName: '', petType: '', serviceType: '', appointmentTime: '', remark: '' })
|
||||
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 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 raw = newAppt.value.appointmentTime || ''
|
||||
if (!raw.includes('T')) return ''
|
||||
@ -291,23 +298,80 @@ const appointmentTime = computed(() => {
|
||||
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 date = e?.detail?.value || ''
|
||||
if (!date) {
|
||||
selectedDateStr.value = ''
|
||||
newAppt.value.appointmentTime = ''
|
||||
availableTimes.value = []
|
||||
return
|
||||
}
|
||||
const time = normalizeToHalfHour(suggestHalfHourForYMD(date))
|
||||
newAppt.value.appointmentTime = `${date}T${time}`
|
||||
selectedDateStr.value = date
|
||||
loadAvailableSlots()
|
||||
}
|
||||
|
||||
const onAppointmentTimeOnlyChange = (e) => {
|
||||
const idx = Number(e.detail.value)
|
||||
const time = HALF_HOUR_TIME_SLOTS[idx]
|
||||
const date = appointmentDate.value
|
||||
if (!date) { uni.showToast({ title: '请先选择日期', icon: 'none' }); return }
|
||||
const time = availableTimes.value[idx]
|
||||
const date = selectedDateStr.value
|
||||
if (!date) {
|
||||
uni.showToast({ title: '请先选择日期', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!time) return
|
||||
newAppt.value.appointmentTime = `${date}T${time}`
|
||||
}
|
||||
|
||||
@ -376,6 +440,11 @@ const confirmNewAppt = async () => {
|
||||
if (!a.petType) { 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 (!availableTimes.value.includes(appointmentTime.value)) {
|
||||
uni.showToast({ title: '该时段不可预约,请重新选择', icon: 'none' })
|
||||
await loadAvailableSlots()
|
||||
return
|
||||
}
|
||||
const row = orderedStores.value[selectedStoreIndex.value]
|
||||
const storeId = row?.id
|
||||
if (!storeId) {
|
||||
@ -417,11 +486,13 @@ const loadMyPets = async () => {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
selectedDateStr.value = ymdLocal()
|
||||
await initStoresAndLocation()
|
||||
if (orderedStores.value.length) {
|
||||
await loadServiceTypesForSelected()
|
||||
}
|
||||
await loadMyPets()
|
||||
await loadAvailableSlots()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@ -107,7 +107,7 @@
|
||||
<view v-if="filteredOrders.length === 0" class="empty"><text>暂无数据</text></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>
|
||||
</view>
|
||||
|
||||
@ -144,23 +144,25 @@
|
||||
<view class="c-field">
|
||||
<text class="app-form-label">预约时间</text>
|
||||
<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">
|
||||
<text :class="{ 'app-form-placeholder': !appointmentDate }">{{ appointmentDate || '日期' }}</text>
|
||||
<text :class="{ 'app-form-placeholder': !staffApptDateStr }">{{ staffApptDateStr || '日期' }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<picker
|
||||
mode="selector"
|
||||
:range="HALF_HOUR_TIME_SLOTS"
|
||||
:value="halfHourTimeIndex"
|
||||
@change="onAppointmentTimeOnlyChange"
|
||||
:range="staffAvailableTimes"
|
||||
:value="staffSlotPickerIndex"
|
||||
:disabled="!staffAvailableTimes.length"
|
||||
@change="onStaffApptTimeChange"
|
||||
class="c-time-half"
|
||||
>
|
||||
<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>
|
||||
</picker>
|
||||
</view>
|
||||
<text class="c-store-hint home-slot-hint">半小时一号源,约满不可选</text>
|
||||
</view>
|
||||
<view class="c-field">
|
||||
<text class="app-form-label">备注(可选)</text>
|
||||
@ -184,18 +186,20 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
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 { getUserSession, getStoreSession } from '../../utils/session.js'
|
||||
import { useNavigator } from '../../composables/useNavigator.js'
|
||||
import { formatDateTimeCN } from '../../utils/datetime.js'
|
||||
import { getAppointmentStatusText } from '../../utils/appointment.js'
|
||||
import {
|
||||
HALF_HOUR_TIME_SLOTS,
|
||||
normalizeToHalfHour,
|
||||
halfHourPickerIndex,
|
||||
suggestHalfHourForYMD
|
||||
} from '../../utils/halfHourTime.js'
|
||||
import { normalizeToHalfHour, ymdLocal } from '../../utils/halfHourTime.js'
|
||||
|
||||
const userInfo = getUserSession()
|
||||
const storeInfo = getStoreSession()
|
||||
@ -232,10 +236,6 @@ const petTypes = [
|
||||
]
|
||||
|
||||
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 raw = newAppt.value.appointmentTime || ''
|
||||
if (!raw.includes('T')) return ''
|
||||
@ -243,7 +243,16 @@ const appointmentTime = computed(() => {
|
||||
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 => {
|
||||
if (currentStatus.value === 'new') return o.status === 'new'
|
||||
@ -252,21 +261,70 @@ const filteredOrders = computed(() => orders.value.filter(o => {
|
||||
return true
|
||||
}))
|
||||
|
||||
const onAppointmentDateChange = (e) => {
|
||||
const date = e?.detail?.value || ''
|
||||
if (!date) {
|
||||
newAppt.value.appointmentTime = ''
|
||||
const loadStaffAvailableSlots = async () => {
|
||||
if (!storeInfo?.id) {
|
||||
staffAvailableTimes.value = []
|
||||
return
|
||||
}
|
||||
const time = normalizeToHalfHour(suggestHalfHourForYMD(date))
|
||||
newAppt.value.appointmentTime = `${date}T${time}`
|
||||
const date = staffApptDateStr.value || ymdLocal()
|
||||
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 time = HALF_HOUR_TIME_SLOTS[idx]
|
||||
const date = appointmentDate.value
|
||||
if (!date) { uni.showToast({ title: '请先选择日期', icon: 'none' }); return }
|
||||
const time = staffAvailableTimes.value[idx]
|
||||
const date = staffApptDateStr.value
|
||||
if (!date) {
|
||||
uni.showToast({ title: '请先选择日期', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!time) return
|
||||
newAppt.value.appointmentTime = `${date}T${time}`
|
||||
}
|
||||
|
||||
@ -362,6 +420,11 @@ const confirmNewAppt = async () => {
|
||||
if (!a.petType) { 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 (!staffAvailableTimes.value.includes(appointmentTime.value)) {
|
||||
uni.showToast({ title: '该时段不可预约,请重新选择', icon: 'none' })
|
||||
await loadStaffAvailableSlots()
|
||||
return
|
||||
}
|
||||
creatingAppt.value = true
|
||||
const res = await createAppointment({ ...a, storeId: storeInfo.id, userId: userInfo.id })
|
||||
creatingAppt.value = false
|
||||
@ -469,6 +532,13 @@ onShow(() => {
|
||||
|
||||
.c-field { margin-bottom: 16px; }
|
||||
.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-half { flex: 1; }
|
||||
.home-remark-textarea { min-height: 80px; line-height: 1.5; }
|
||||
|
||||
@ -66,6 +66,37 @@
|
||||
</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">
|
||||
<button
|
||||
class="van-button van-button--primary van-button--block store-save-btn"
|
||||
@ -86,7 +117,8 @@
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import AppIcon from '../../components/AppIcon.vue'
|
||||
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'
|
||||
|
||||
defineEmits(['change-page'])
|
||||
@ -118,9 +150,33 @@ const form = ref({
|
||||
address: '',
|
||||
intro: '',
|
||||
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 toCoord = (v) => {
|
||||
@ -151,6 +207,12 @@ const pickAddress = () => {
|
||||
}
|
||||
|
||||
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
|
||||
const res = await updateStore({ id: storeInfo.id, ...form.value })
|
||||
saving.value = false
|
||||
@ -163,15 +225,32 @@ const saveStore = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
form.value = {
|
||||
onMounted(async () => {
|
||||
const base = {
|
||||
name: storeInfo.name || '',
|
||||
phone: storeInfo.phone || '',
|
||||
address: storeInfo.address || '',
|
||||
intro: storeInfo.intro || '',
|
||||
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>
|
||||
|
||||
@ -361,4 +440,23 @@ onMounted(() => {
|
||||
font-size: 12px;
|
||||
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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user