fix: 修复预约及页面展示
This commit is contained in:
parent
2497204de1
commit
e91f140bac
@ -64,7 +64,7 @@
|
|||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
<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="selectedDateStr" @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">
|
||||||
@ -73,14 +73,14 @@
|
|||||||
</picker>
|
</picker>
|
||||||
<picker
|
<picker
|
||||||
mode="selector"
|
mode="selector"
|
||||||
:range="availableTimes"
|
:range="availableSlotLabels"
|
||||||
:value="slotPickerIndex"
|
:value="slotPickerIndex"
|
||||||
:disabled="!availableTimes.length"
|
:disabled="!availableTimes.length"
|
||||||
@change="onAppointmentTimeOnlyChange"
|
@change="onAppointmentTimeOnlyChange"
|
||||||
class="c-time-half"
|
class="c-time-half c-time-half--slot"
|
||||||
>
|
>
|
||||||
<view class="app-form-input app-form-picker">
|
<view class="app-form-input app-form-picker">
|
||||||
<text :class="{ 'app-form-placeholder': !appointmentTime && !loadingSlots }">{{ loadingSlots ? '加载中…' : (appointmentTime || '时间') }}</text>
|
<text class="slot-range-text" :class="{ 'app-form-placeholder': !appointmentTime && !loadingSlots }">{{ loadingSlots ? '加载中…' : (selectedSlotRangeLabel || '选择时段') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
@ -108,7 +108,7 @@ import {
|
|||||||
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 { normalizeToHalfHour, ymdLocal } from '../../utils/halfHourTime.js'
|
import { normalizeToHalfHour, ymdLocal, formatHalfHourSlotRange } from '../../utils/halfHourTime.js'
|
||||||
|
|
||||||
const userInfo = getUserSession()
|
const userInfo = getUserSession()
|
||||||
const storeInfo = getStoreSession()
|
const storeInfo = getStoreSession()
|
||||||
@ -240,7 +240,7 @@ const creatingAppt = ref(false)
|
|||||||
const selectedDateStr = ref(ymdLocal())
|
const selectedDateStr = ref(ymdLocal())
|
||||||
const availableTimes = ref([])
|
const availableTimes = ref([])
|
||||||
const loadingSlots = ref(false)
|
const loadingSlots = ref(false)
|
||||||
const bookingWindowHint = ref('半小时为一号源,同一时段仅接待一单;已满或已过期不可选')
|
const bookingWindowHint = ref('请选择半小时时间段;同一时段仅接待一单,已满或已过期不可选')
|
||||||
|
|
||||||
const normalizeText = (s) => (s || '').toString().trim().toLowerCase()
|
const normalizeText = (s) => (s || '').toString().trim().toLowerCase()
|
||||||
|
|
||||||
@ -304,6 +304,15 @@ const slotPickerIndex = computed(() => {
|
|||||||
return i >= 0 ? i : 0
|
return i >= 0 ? i : 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** 滚轮选项展示为「09:00–09:30」 */
|
||||||
|
const availableSlotLabels = computed(() =>
|
||||||
|
availableTimes.value.map((t) => formatHalfHourSlotRange(t))
|
||||||
|
)
|
||||||
|
|
||||||
|
const selectedSlotRangeLabel = computed(() =>
|
||||||
|
appointmentTime.value ? formatHalfHourSlotRange(appointmentTime.value) : ''
|
||||||
|
)
|
||||||
|
|
||||||
const loadAvailableSlots = async () => {
|
const loadAvailableSlots = async () => {
|
||||||
const row = orderedStores.value[selectedStoreIndex.value]
|
const row = orderedStores.value[selectedStoreIndex.value]
|
||||||
const storeId = row?.id
|
const storeId = row?.id
|
||||||
@ -326,7 +335,7 @@ const loadAvailableSlots = async () => {
|
|||||||
if (ds != null && le != null) {
|
if (ds != null && le != null) {
|
||||||
const a = String(ds).slice(0, 5)
|
const a = String(ds).slice(0, 5)
|
||||||
const b = String(le).slice(0, 5)
|
const b = String(le).slice(0, 5)
|
||||||
bookingWindowHint.value = `本店放号 ${a}~${b},半小时一号源;同一时段仅一单,已满或已过不可选`
|
bookingWindowHint.value = `本店可约 ${a}~${b};以下为半小时时段,同一时段仅一单,已满或已过不可选`
|
||||||
}
|
}
|
||||||
availableTimes.value = res.data.slots.filter((s) => s.available).map((s) => s.time)
|
availableTimes.value = res.data.slots.filter((s) => s.available).map((s) => s.time)
|
||||||
if (!availableTimes.value.length) {
|
if (!availableTimes.value.length) {
|
||||||
@ -537,7 +546,11 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
.c-field { margin-bottom: 16px; }
|
.c-field { margin-bottom: 16px; }
|
||||||
.c-time-row { display: flex; gap: 10px; }
|
.c-time-row { display: flex; gap: 10px; }
|
||||||
.c-time-half { flex: 1; }
|
.c-time-half { flex: 1; min-width: 0; }
|
||||||
|
.c-time-half--slot .slot-range-text {
|
||||||
|
font-size: 12px;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
.pet-name-row {
|
.pet-name-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -142,7 +142,7 @@
|
|||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
<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="staffApptDateStr" @change="onStaffApptDateChange" 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">
|
||||||
@ -151,18 +151,18 @@
|
|||||||
</picker>
|
</picker>
|
||||||
<picker
|
<picker
|
||||||
mode="selector"
|
mode="selector"
|
||||||
:range="staffAvailableTimes"
|
:range="staffAvailableSlotLabels"
|
||||||
:value="staffSlotPickerIndex"
|
:value="staffSlotPickerIndex"
|
||||||
:disabled="!staffAvailableTimes.length"
|
:disabled="!staffAvailableTimes.length"
|
||||||
@change="onStaffApptTimeChange"
|
@change="onStaffApptTimeChange"
|
||||||
class="c-time-half"
|
class="c-time-half c-time-half--slot"
|
||||||
>
|
>
|
||||||
<view class="app-form-input app-form-picker">
|
<view class="app-form-input app-form-picker">
|
||||||
<text :class="{ 'app-form-placeholder': !appointmentTime && !staffLoadingSlots }">{{ staffLoadingSlots ? '加载中…' : (appointmentTime || '时间') }}</text>
|
<text class="home-slot-range-text" :class="{ 'app-form-placeholder': !appointmentTime && !staffLoadingSlots }">{{ staffLoadingSlots ? '加载中…' : (staffSelectedSlotRangeLabel || '选择时段') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
<text class="c-store-hint home-slot-hint">半小时一号源,约满不可选</text>
|
<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>
|
||||||
@ -199,7 +199,7 @@ 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 { normalizeToHalfHour, ymdLocal } from '../../utils/halfHourTime.js'
|
import { normalizeToHalfHour, ymdLocal, formatHalfHourSlotRange } from '../../utils/halfHourTime.js'
|
||||||
|
|
||||||
const userInfo = getUserSession()
|
const userInfo = getUserSession()
|
||||||
const storeInfo = getStoreSession()
|
const storeInfo = getStoreSession()
|
||||||
@ -254,6 +254,14 @@ const staffSlotPickerIndex = computed(() => {
|
|||||||
return i >= 0 ? i : 0
|
return i >= 0 ? i : 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const staffAvailableSlotLabels = computed(() =>
|
||||||
|
staffAvailableTimes.value.map((t) => formatHalfHourSlotRange(t))
|
||||||
|
)
|
||||||
|
|
||||||
|
const staffSelectedSlotRangeLabel = computed(() =>
|
||||||
|
appointmentTime.value ? formatHalfHourSlotRange(appointmentTime.value) : ''
|
||||||
|
)
|
||||||
|
|
||||||
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'
|
||||||
if (currentStatus.value === 'doing') return o.status === 'doing'
|
if (currentStatus.value === 'doing') return o.status === 'doing'
|
||||||
@ -540,7 +548,11 @@ onShow(() => {
|
|||||||
line-height: 1.4;
|
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; min-width: 0; }
|
||||||
|
.c-time-half--slot .home-slot-range-text {
|
||||||
|
font-size: 12px;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
.home-remark-textarea { min-height: 80px; line-height: 1.5; }
|
.home-remark-textarea { min-height: 80px; line-height: 1.5; }
|
||||||
|
|
||||||
/* B端 Tab */
|
/* B端 Tab */
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 店铺管理 -->
|
<!-- 店铺管理(老板) -->
|
||||||
<view v-if="userInfo.role === 'boss'" class="menu-group">
|
<view v-if="userInfo.role === 'boss'" class="menu-group">
|
||||||
<text class="menu-label">店铺管理</text>
|
<text class="menu-label">店铺管理</text>
|
||||||
<view class="menu-card">
|
<view class="menu-card">
|
||||||
@ -37,6 +37,18 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 员工:仅门店设置(含营业时间) -->
|
||||||
|
<view v-else-if="userInfo.role === 'staff'" class="menu-group">
|
||||||
|
<text class="menu-label">门店</text>
|
||||||
|
<view class="menu-card">
|
||||||
|
<view class="menu-item" @click="goStorePage">
|
||||||
|
<view class="menu-icon-wrap"><AppIcon name="store" :size="16" color="#666660" /></view>
|
||||||
|
<text class="menu-text">店铺设置</text>
|
||||||
|
<text class="menu-arrow">›</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 个人 -->
|
<!-- 个人 -->
|
||||||
<view class="menu-group">
|
<view class="menu-group">
|
||||||
<text class="menu-label">个人中心</text>
|
<text class="menu-label">个人中心</text>
|
||||||
|
|||||||
@ -1,103 +1,106 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page-shell store-page">
|
<view class="page-shell store-page">
|
||||||
<view class="store-nav nav-gradient" :style="navSafeStyle">
|
<view class="store-nav nav-gradient" :style="navSafeStyle">
|
||||||
<view class="nav-back" @click="goBackToMine"><AppIcon name="back" :size="18" color="#ffffff" /></view>
|
<view class="nav-back" @click="goBackToMine"><AppIcon name="back" :size="18" color="#ffffff" /></view>
|
||||||
<text class="nav-title">店铺设置</text>
|
<text class="nav-title">店铺设置</text>
|
||||||
<view class="nav-placeholder"></view>
|
<view class="nav-placeholder"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<div class="store-body">
|
<view class="store-body">
|
||||||
<!-- 说明条:填充顶部视觉,交代用途 -->
|
<view class="store-hero">
|
||||||
<div class="store-hero">
|
|
||||||
<view class="store-hero-icon" aria-hidden="true">
|
<view class="store-hero-icon" aria-hidden="true">
|
||||||
<AppIcon name="store" :size="22" color="#15803d" />
|
<AppIcon name="store" :size="22" color="#15803d" />
|
||||||
</view>
|
</view>
|
||||||
<div class="store-hero-text">
|
<view class="store-hero-text">
|
||||||
<div class="store-hero-title">门店资料</div>
|
<text class="store-hero-title">门店资料</text>
|
||||||
<div class="store-hero-desc">以下信息会用于预约展示与客户联系,建议保持准确、易读。</div>
|
<text class="store-hero-desc">请先设置「营业时间」,再完善名称、电话与地址。营业时间即客户线上预约可选的时段范围(半小时一号)。</text>
|
||||||
</div>
|
</view>
|
||||||
</div>
|
</view>
|
||||||
|
|
||||||
<div class="store-card">
|
<!-- 营业时间置顶,避免被误认为没有该配置 -->
|
||||||
<div class="store-card-head">
|
<view class="store-card store-card--hours">
|
||||||
<span class="store-card-kicker">基础信息</span>
|
<view class="store-card-head">
|
||||||
</div>
|
<text class="store-card-title">营业时间</text>
|
||||||
|
<text class="store-card-sub">客户可预约时段:从「开始」到「结束」之间的半点档均可放号(与挂号类似)</text>
|
||||||
<div class="store-field">
|
</view>
|
||||||
<div class="store-field-label">
|
<view class="store-field">
|
||||||
<span class="store-ico"><AppIcon name="store" :size="15" color="#475569" /></span>
|
<view class="store-field-label">
|
||||||
<text>店铺名称</text>
|
<span class="store-ico"><AppIcon name="service" :size="15" color="#475569" /></span>
|
||||||
</div>
|
<text>开始时间</text>
|
||||||
<input v-model="form.name" class="van-field store-input" placeholder="请输入店铺名称" />
|
</view>
|
||||||
</div>
|
<text class="store-field-tip">当日第一个可预约的半点(例如 09:00)</text>
|
||||||
|
|
||||||
<div class="store-field">
|
|
||||||
<div class="store-field-label">
|
|
||||||
<span class="store-ico"><AppIcon name="phone" :size="15" color="#475569" /></span>
|
|
||||||
<text>联系电话</text>
|
|
||||||
</div>
|
|
||||||
<input v-model="form.phone" type="tel" class="van-field store-input" placeholder="请输入联系电话" maxlength="20" />
|
|
||||||
</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>
|
|
||||||
<div class="address-row">
|
|
||||||
<input v-model="form.address" class="van-field store-input address-input" placeholder="输入地址或点右侧选点" />
|
|
||||||
<button type="button" class="pick-location-btn" :disabled="pickingLocation" @click="pickAddress">
|
|
||||||
地图选点
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div v-if="hasMapPin" class="geo-hint">已选地图位置,可再微调上方文字后保存</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="store-field store-field-last">
|
|
||||||
<div class="store-field-label">
|
|
||||||
<span class="store-ico"><AppIcon name="report" :size="15" color="#475569" /></span>
|
|
||||||
<text>简介</text>
|
|
||||||
</div>
|
|
||||||
<textarea
|
|
||||||
v-model="form.intro"
|
|
||||||
class="van-field store-input intro-textarea"
|
|
||||||
placeholder="一句话介绍门店特色、服务亮点等"
|
|
||||||
/>
|
|
||||||
</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">
|
<picker mode="selector" :range="HALF_HOUR_TIME_SLOTS" :value="bookingStartIdx" @change="onBookingStartChange">
|
||||||
<view class="app-form-input app-form-picker store-picker-like">
|
<view class="app-form-input app-form-picker store-picker-like">
|
||||||
<text>{{ form.bookingDayStart || '请选择' }}</text>
|
<text>{{ form.bookingDayStart || '请选择' }}</text>
|
||||||
<text class="app-form-arrow">›</text>
|
<text class="app-form-arrow">›</text>
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
</picker>
|
||||||
</div>
|
</view>
|
||||||
<div class="store-field store-field-last">
|
<view class="store-field store-field-last">
|
||||||
<div class="store-field-label">
|
<view class="store-field-label">
|
||||||
<span class="store-ico"><AppIcon name="pin" :size="15" color="#475569" /></span>
|
<span class="store-ico"><AppIcon name="service" :size="15" color="#475569" /></span>
|
||||||
<text>每日最后一个号源</text>
|
<text>结束时间</text>
|
||||||
</div>
|
</view>
|
||||||
|
<text class="store-field-tip">当日最后一个可预约的半点起始时刻(例如 21:30 表示最晚可约 21:00–21:30 这一档)</text>
|
||||||
<picker mode="selector" :range="HALF_HOUR_TIME_SLOTS" :value="bookingLastIdx" @change="onBookingLastChange">
|
<picker mode="selector" :range="HALF_HOUR_TIME_SLOTS" :value="bookingLastIdx" @change="onBookingLastChange">
|
||||||
<view class="app-form-input app-form-picker store-picker-like">
|
<view class="app-form-input app-form-picker store-picker-like">
|
||||||
<text>{{ form.bookingLastSlotStart || '请选择' }}</text>
|
<text>{{ form.bookingLastSlotStart || '请选择' }}</text>
|
||||||
<text class="app-form-arrow">›</text>
|
<text class="app-form-arrow">›</text>
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
</picker>
|
||||||
<div class="booking-hint">半小时一档;末号须不早于首号。保存后对新建预约生效。</div>
|
<view class="booking-hint">结束须不早于开始。保存后对新建预约生效。</view>
|
||||||
</div>
|
</view>
|
||||||
</div>
|
</view>
|
||||||
|
|
||||||
<div class="store-actions">
|
<view class="store-card" style="margin-top: 14px">
|
||||||
|
<view class="store-card-head">
|
||||||
|
<text class="store-card-kicker">基础信息</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="store-field">
|
||||||
|
<view class="store-field-label">
|
||||||
|
<span class="store-ico"><AppIcon name="store" :size="15" color="#475569" /></span>
|
||||||
|
<text>店铺名称</text>
|
||||||
|
</view>
|
||||||
|
<input v-model="form.name" class="van-field store-input" placeholder="请输入店铺名称" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="store-field">
|
||||||
|
<view class="store-field-label">
|
||||||
|
<span class="store-ico"><AppIcon name="phone" :size="15" color="#475569" /></span>
|
||||||
|
<text>联系电话</text>
|
||||||
|
</view>
|
||||||
|
<input v-model="form.phone" type="tel" class="van-field store-input" placeholder="请输入联系电话" maxlength="20" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="store-field">
|
||||||
|
<view class="store-field-label">
|
||||||
|
<span class="store-ico"><AppIcon name="pin" :size="15" color="#475569" /></span>
|
||||||
|
<text>地址</text>
|
||||||
|
</view>
|
||||||
|
<view class="address-row">
|
||||||
|
<input v-model="form.address" class="van-field store-input address-input" placeholder="输入地址或点右侧选点" />
|
||||||
|
<button type="button" class="pick-location-btn" :disabled="pickingLocation" @click="pickAddress">
|
||||||
|
地图选点
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
<view v-if="hasMapPin" class="geo-hint">已选地图位置,可再微调上方文字后保存</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="store-field store-field-last">
|
||||||
|
<view class="store-field-label">
|
||||||
|
<span class="store-ico"><AppIcon name="report" :size="15" color="#475569" /></span>
|
||||||
|
<text>简介</text>
|
||||||
|
</view>
|
||||||
|
<textarea
|
||||||
|
v-model="form.intro"
|
||||||
|
class="van-field store-input intro-textarea"
|
||||||
|
placeholder="一句话介绍门店特色、服务亮点等"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view 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"
|
||||||
:loading="saving"
|
:loading="saving"
|
||||||
@ -105,12 +108,12 @@
|
|||||||
>
|
>
|
||||||
保存设置
|
保存设置
|
||||||
</button>
|
</button>
|
||||||
<div class="store-actions-hint">保存后立即生效,并写入本地缓存。</div>
|
<view class="store-actions-hint">保存后立即生效,并写入本地缓存。</view>
|
||||||
</div>
|
</view>
|
||||||
|
|
||||||
<div class="store-footer-tip">宠伴生活馆 · 商家版</div>
|
<view class="store-footer-tip">宠伴生活馆 · 商家版</view>
|
||||||
</div>
|
</view>
|
||||||
</div>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -210,7 +213,7 @@ const saveStore = async () => {
|
|||||||
const i0 = HALF_HOUR_TIME_SLOTS.indexOf(form.value.bookingDayStart)
|
const i0 = HALF_HOUR_TIME_SLOTS.indexOf(form.value.bookingDayStart)
|
||||||
const i1 = HALF_HOUR_TIME_SLOTS.indexOf(form.value.bookingLastSlotStart)
|
const i1 = HALF_HOUR_TIME_SLOTS.indexOf(form.value.bookingLastSlotStart)
|
||||||
if (i0 < 0 || i1 < 0 || i1 < i0) {
|
if (i0 < 0 || i1 < 0 || i1 < i0) {
|
||||||
uni.showToast({ title: '末号须不早于首号', icon: 'none' })
|
uni.showToast({ title: '结束时间须不早于开始时间', icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
saving.value = true
|
saving.value = true
|
||||||
@ -309,13 +312,19 @@ onMounted(async () => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
.store-hero-text {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
.store-hero-title {
|
.store-hero-title {
|
||||||
|
display: block;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #14532d;
|
color: #14532d;
|
||||||
letter-spacing: 0.02em;
|
letter-spacing: 0.02em;
|
||||||
}
|
}
|
||||||
.store-hero-desc {
|
.store-hero-desc {
|
||||||
|
display: block;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
@ -330,6 +339,10 @@ onMounted(async () => {
|
|||||||
padding: 4px 4px 8px;
|
padding: 4px 4px 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
.store-card--hours {
|
||||||
|
border-color: #86efac;
|
||||||
|
box-shadow: 0 8px 22px rgba(34, 197, 94, 0.12);
|
||||||
|
}
|
||||||
.store-card-head {
|
.store-card-head {
|
||||||
padding: 14px 14px 6px;
|
padding: 14px 14px 6px;
|
||||||
}
|
}
|
||||||
@ -339,6 +352,20 @@ onMounted(async () => {
|
|||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
}
|
}
|
||||||
|
.store-card-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #14532d;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
.store-card-sub {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
.store-field {
|
.store-field {
|
||||||
padding: 12px 12px 4px;
|
padding: 12px 12px 4px;
|
||||||
@ -350,11 +377,18 @@ onMounted(async () => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 6px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #374151;
|
color: #374151;
|
||||||
}
|
}
|
||||||
|
.store-field-tip {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.45;
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
.store-ico {
|
.store-ico {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
|
|||||||
@ -42,6 +42,30 @@ export function halfHourPickerIndex(hhmm) {
|
|||||||
|
|
||||||
const pad2 = (n) => String(n).padStart(2, '0')
|
const pad2 = (n) => String(n).padStart(2, '0')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 半小时挂号:展示为「开始–结束」时间段(如 09:00–09:30)。
|
||||||
|
* 末档 23:30 结束展示为 23:30–24:00。
|
||||||
|
*/
|
||||||
|
export function formatHalfHourSlotRange(startHHmm) {
|
||||||
|
if (startHHmm == null || startHHmm === '') return ''
|
||||||
|
const m = String(startHHmm).trim().match(/^(\d{1,2}):(\d{2})$/)
|
||||||
|
if (!m) return String(startHHmm)
|
||||||
|
let h = parseInt(m[1], 10)
|
||||||
|
let mi = parseInt(m[2], 10)
|
||||||
|
if (Number.isNaN(h) || Number.isNaN(mi)) return String(startHHmm)
|
||||||
|
h = Math.min(23, Math.max(0, h))
|
||||||
|
mi = Math.min(59, Math.max(0, mi))
|
||||||
|
const startM = h * 60 + mi
|
||||||
|
const endM = startM + 30
|
||||||
|
const startStr = `${pad2(h)}:${pad2(mi)}`
|
||||||
|
if (endM >= 24 * 60) {
|
||||||
|
return `${startStr}–24:00`
|
||||||
|
}
|
||||||
|
const endH = Math.floor(endM / 60)
|
||||||
|
const endMi = endM % 60
|
||||||
|
return `${startStr}–${pad2(endH)}:${pad2(endMi)}`
|
||||||
|
}
|
||||||
|
|
||||||
/** 本地日历 YYYY-MM-DD */
|
/** 本地日历 YYYY-MM-DD */
|
||||||
export function ymdLocal(d = new Date()) {
|
export function ymdLocal(d = new Date()) {
|
||||||
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`
|
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user