diff --git a/src/pages/appointment/CustAppointmentCreate.vue b/src/pages/appointment/CustAppointmentCreate.vue
index 4a2e4dc..ffdf371 100644
--- a/src/pages/appointment/CustAppointmentCreate.vue
+++ b/src/pages/appointment/CustAppointmentCreate.vue
@@ -68,7 +68,13 @@
{{ appointmentDate || '日期' }}
-
+
{{ appointmentTime || '时间' }}
@@ -90,6 +96,12 @@ import { createAppointment, getServiceTypeList, getPetList, getStoreList } from
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'
const userInfo = getUserSession()
const storeInfo = getStoreSession()
@@ -239,17 +251,25 @@ const appointmentDate = computed(() => {
const appointmentTime = computed(() => {
const raw = newAppt.value.appointmentTime || ''
if (!raw.includes('T')) return ''
- return (raw.split('T')[1] || '').slice(0, 5)
+ const part = (raw.split('T')[1] || '').slice(0, 5)
+ return normalizeToHalfHour(part)
})
+const halfHourTimeIndex = computed(() => halfHourPickerIndex(appointmentTime.value))
+
const onAppointmentDateChange = (e) => {
const date = e?.detail?.value || ''
- const time = appointmentTime.value || '00:00'
- newAppt.value.appointmentTime = date ? `${date}T${time}` : ''
+ if (!date) {
+ newAppt.value.appointmentTime = ''
+ return
+ }
+ const time = normalizeToHalfHour(suggestHalfHourForYMD(date))
+ newAppt.value.appointmentTime = `${date}T${time}`
}
const onAppointmentTimeOnlyChange = (e) => {
- const time = e?.detail?.value || ''
+ 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 }
newAppt.value.appointmentTime = `${date}T${time}`
diff --git a/src/pages/home/Home.vue b/src/pages/home/Home.vue
index ef7feb0..470a165 100644
--- a/src/pages/home/Home.vue
+++ b/src/pages/home/Home.vue
@@ -147,7 +147,13 @@
{{ appointmentDate || '日期' }}
-
+
{{ appointmentTime || '时间' }}
@@ -182,6 +188,12 @@ 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'
const userInfo = getUserSession()
const storeInfo = getStoreSession()
@@ -225,9 +237,12 @@ const appointmentDate = computed(() => {
const appointmentTime = computed(() => {
const raw = newAppt.value.appointmentTime || ''
if (!raw.includes('T')) return ''
- return (raw.split('T')[1] || '').slice(0, 5)
+ const part = (raw.split('T')[1] || '').slice(0, 5)
+ return normalizeToHalfHour(part)
})
+const halfHourTimeIndex = computed(() => halfHourPickerIndex(appointmentTime.value))
+
const filteredOrders = computed(() => orders.value.filter(o => {
if (currentStatus.value === 'new') return o.status === 'new'
if (currentStatus.value === 'doing') return o.status === 'doing'
@@ -237,12 +252,17 @@ const filteredOrders = computed(() => orders.value.filter(o => {
const onAppointmentDateChange = (e) => {
const date = e?.detail?.value || ''
- const time = appointmentTime.value || '00:00'
- newAppt.value.appointmentTime = date ? `${date}T${time}` : ''
+ if (!date) {
+ newAppt.value.appointmentTime = ''
+ return
+ }
+ const time = normalizeToHalfHour(suggestHalfHourForYMD(date))
+ newAppt.value.appointmentTime = `${date}T${time}`
}
const onAppointmentTimeOnlyChange = (e) => {
- const time = e?.detail?.value || ''
+ 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 }
newAppt.value.appointmentTime = `${date}T${time}`
diff --git a/src/pages/report/Report.vue b/src/pages/report/Report.vue
index eb2afa6..d7981c4 100644
--- a/src/pages/report/Report.vue
+++ b/src/pages/report/Report.vue
@@ -33,7 +33,13 @@
{{ serviceDate || '日期' }}
-
+
{{ serviceTimePart || '时间' }}
@@ -117,6 +123,13 @@ import TabBar from '../../components/TabBar.vue'
import AppIcon from '../../components/AppIcon.vue'
import { getUserSession, getStoreSession } from '../../utils/session.js'
import { useNavigator } from '../../composables/useNavigator.js'
+import {
+ HALF_HOUR_TIME_SLOTS,
+ DEFAULT_HALF_HOUR_TIME,
+ normalizeToHalfHour,
+ halfHourPickerIndex,
+ suggestHalfHourForYMD
+} from '../../utils/halfHourTime.js'
const userInfo = getUserSession()
const storeInfo = getStoreSession()
@@ -196,17 +209,25 @@ const serviceDate = computed(() => {
const serviceTimePart = computed(() => {
const raw = report.value.appointmentTime || ''
if (!raw.includes('T')) return ''
- return (raw.split('T')[1] || '').slice(0, 5)
+ const part = (raw.split('T')[1] || '').slice(0, 5)
+ return normalizeToHalfHour(part)
})
+const halfHourServiceTimeIndex = computed(() => halfHourPickerIndex(serviceTimePart.value))
+
const onServiceDateChange = (e) => {
const date = e?.detail?.value || ''
- const time = serviceTimePart.value || '00:00'
- report.value.appointmentTime = date ? `${date}T${time}` : ''
+ if (!date) {
+ report.value.appointmentTime = ''
+ return
+ }
+ const time = normalizeToHalfHour(suggestHalfHourForYMD(date))
+ report.value.appointmentTime = `${date}T${time}`
}
const onServiceTimeChange = (e) => {
- const time = e?.detail?.value || ''
+ const idx = Number(e.detail.value)
+ const time = HALF_HOUR_TIME_SLOTS[idx]
const date = serviceDate.value
if (!date) { uni.showToast({ title: '请先选择日期', icon: 'none' }); return }
report.value.appointmentTime = `${date}T${time}`
@@ -262,8 +283,8 @@ onMounted(async () => {
const raw = String(prefill.appointmentTime)
if (raw.includes('T')) {
const [d, rest] = raw.split('T')
- const hm = (rest || '').match(/^(\d{1,2}:\d{2})/)?.[1] || '00:00'
- report.value.appointmentTime = `${d}T${hm}`
+ const hm = (rest || '').match(/^(\d{1,2}:\d{2})/)?.[1] || DEFAULT_HALF_HOUR_TIME
+ report.value.appointmentTime = `${d}T${normalizeToHalfHour(hm)}`
}
}
uni.removeStorageSync('petstore_report_prefill')
diff --git a/src/utils/halfHourTime.js b/src/utils/halfHourTime.js
new file mode 100644
index 0000000..b8e4967
--- /dev/null
+++ b/src/utils/halfHourTime.js
@@ -0,0 +1,72 @@
+/** 未选时间时的默认展示与选中日期的默认时刻 */
+export const DEFAULT_HALF_HOUR_TIME = '09:00'
+
+/** 全天半小时间隔:00:00 … 23:30 */
+export const HALF_HOUR_TIME_SLOTS = (() => {
+ const a = []
+ for (let h = 0; h < 24; h++) {
+ const p = (n) => String(n).padStart(2, '0')
+ a.push(`${p(h)}:00`)
+ a.push(`${p(h)}:30`)
+ }
+ return a
+})()
+
+/**
+ * 将 HH:mm 规范到最近的半点档;空值或无法解析时返回 {@link DEFAULT_HALF_HOUR_TIME}
+ */
+export function normalizeToHalfHour(hhmm) {
+ if (hhmm == null || hhmm === '') return DEFAULT_HALF_HOUR_TIME
+ if (typeof hhmm !== 'string') return DEFAULT_HALF_HOUR_TIME
+ const m = hhmm.match(/^(\d{1,2}):(\d{2})$/)
+ if (!m) return DEFAULT_HALF_HOUR_TIME
+ let h = parseInt(m[1], 10)
+ let mi = parseInt(m[2], 10)
+ if (Number.isNaN(h) || Number.isNaN(mi)) return DEFAULT_HALF_HOUR_TIME
+ h = Math.min(23, Math.max(0, h))
+ mi = Math.min(59, Math.max(0, mi))
+ const total = h * 60 + mi
+ const snapped = Math.min(1410, Math.round(total / 30) * 30)
+ const H = Math.floor(snapped / 60)
+ const M = snapped % 60
+ const key = `${String(H).padStart(2, '0')}:${String(M).padStart(2, '0')}`
+ return HALF_HOUR_TIME_SLOTS.includes(key) ? key : DEFAULT_HALF_HOUR_TIME
+}
+
+/** 供 picker mode=selector 的 :value(索引) */
+export function halfHourPickerIndex(hhmm) {
+ const n = normalizeToHalfHour(hhmm)
+ const i = HALF_HOUR_TIME_SLOTS.indexOf(n)
+ return i >= 0 ? i : 0
+}
+
+const pad2 = (n) => String(n).padStart(2, '0')
+
+/** 本地日历 YYYY-MM-DD */
+export function ymdLocal(d = new Date()) {
+ return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`
+}
+
+/**
+ * 当前时刻之后的下一个半点档(含恰落在整点/半点时取该档)。
+ * 若已超过 23:30,返回 null。
+ */
+export function getNextHalfHourAfterNow(now = new Date()) {
+ const total = now.getHours() * 60 + now.getMinutes() + now.getSeconds() / 60
+ let slotM = Math.ceil(total / 30) * 30
+ if (slotM >= 24 * 60) return null
+ const H = Math.floor(slotM / 60)
+ const M = slotM % 60
+ return `${pad2(H)}:${pad2(M)}`
+}
+
+/**
+ * 选中日期的默认时刻:当天 → 当前时刻往后的下一个半点档;其它日期 → 09:00。
+ * 当天已无可用半点时(理论上仅深夜),退回 23:30。
+ */
+export function suggestHalfHourForYMD(dateStr) {
+ if (!dateStr || typeof dateStr !== 'string') return DEFAULT_HALF_HOUR_TIME
+ if (dateStr !== ymdLocal(new Date())) return DEFAULT_HALF_HOUR_TIME
+ const next = getNextHalfHourAfterNow()
+ return next != null ? next : '23:30'
+}