Files
mini-yu/pages/appointments/appointments.vue
lingxiao865 c5af079d8c first commit
2026-02-10 08:05:03 +08:00

237 lines
5.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<!-- 状态筛选 -->
<view class="tabs">
<t-tabs :value="activeTab" @change="onTabChange">
<t-tab-panel value="all" label="全部" />
<t-tab-panel value="pending" label="待确认" />
<t-tab-panel value="confirmed" label="已确认" />
<t-tab-panel value="completed" label="已完成" />
<t-tab-panel value="cancelled" label="已取消" />
</t-tabs>
</view>
<!-- 预约列表 -->
<view class="appointments-list">
<t-loading v-if="loading" loading />
<view v-else-if="appointments.length === 0" class="empty-state">
<t-empty description="暂无预约记录" />
</view>
<view v-else>
<view v-for="appointment in appointments" :key="appointment.id" class="appointment-card">
<view class="appointment-header">
<view class="appointment-status">
<t-tag :theme="getStatusTheme(appointment.status)" size="small">
{{ getStatusText(appointment.status) }}
</t-tag>
</view>
<view class="appointment-date">
{{ formatDate(appointment.created_at) }}
</view>
</view>
<view class="appointment-body">
<view class="appointment-row">
<text class="row-label">时间段</text>
<text class="row-value">
{{ appointment.time_slot ? (appointment.time_slot.date).split('T')[0] : '' }}
{{ appointment.time_slot ? formatTime(appointment.time_slot.start_time) : '' }} -
{{ appointment.time_slot ? formatTime(appointment.time_slot.end_time) : '' }}
</text>
</view>
<view class="appointment-row">
<text class="row-label">人数</text>
<text class="row-value">{{ appointment.people_count }}</text>
</view>
</view>
<view class="appointment-footer" v-if="appointment.status === 'pending'">
<t-button class="btn-outline" size="small" theme="danger" variant="outline"
@click="cancelAppointment(appointment)">
取消预约
</t-button>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { api, type Appointment } from '@/utils/api'
const activeTab = ref('all')
const appointments = ref<Appointment[]>([])
const loading = ref(false)
onMounted(() => {
loadAppointments()
})
// 加载预约列表
const loadAppointments = async () => {
loading.value = true
try {
const params: any = {}
if (activeTab.value !== 'all') {
params.status = activeTab.value
}
appointments.value = await api.appointments.getList(params)
// 调试:打印第一个预约的数据
} catch (error) {
console.error('加载预约失败', error)
} finally {
loading.value = false
}
}
// 切换标签
const onTabChange = (value: any) => {
// TDesign 可能传递对象或字符串
const tabValue = typeof value === 'string' ? value : (value?.value || 'all')
activeTab.value = tabValue
loadAppointments()
}
// 获取状态主题
const getStatusTheme = (status: string) => {
const themes: Record<string, any> = {
pending: 'warning',
confirmed: 'success',
completed: 'primary',
cancelled: 'default'
}
return themes[status] || 'default'
}
// 获取状态文本
const getStatusText = (status: string) => {
const texts: Record<string, string> = {
pending: '待确认',
confirmed: '已确认',
completed: '已完成',
cancelled: '已取消'
}
return texts[status] || status
}
// 格式化日期
const formatDate = (dateStr: string) => {
if (!dateStr) return ''
try {
return dateStr.replace('T', ' ').split('+')[0];
} catch (error) {
console.error('Date format error:', error, dateStr)
return dateStr
}
}
// 格式化时间
const formatTime = (timeStr: string) => {
// 直接提取时间部分,避免时区转换问题
const timePart = timeStr.split('T')[1] || timeStr
const timeWithoutZone = timePart.split('+')[0].split('Z')[0]
const [hours, minutes] = timeWithoutZone.split(':')
return `${hours}:${minutes}`
}
// 取消预约
const cancelAppointment = (appointment: Appointment) => {
uni.showModal({
title: '确认取消',
content: '确定要取消这个预约吗?',
success: async (res) => {
if (res.confirm) {
try {
await api.appointments.cancel(appointment.id)
uni.showToast({
title: '取消成功',
icon: 'success'
})
loadAppointments()
} catch (error) {
console.error('取消预约失败', error)
}
}
}
})
}
</script>
<style scoped>
.container {
height: calc(100vh - var(--window-top));
display: flex;
flex-direction: column;
background: #F8F9FA;
overflow: hidden;
}
.tabs {
flex-shrink: 0;
background: #ffffff;
}
.appointments-list {
flex: 1;
overflow-y: auto;
padding: 20rpx 32rpx;
}
.empty-state {
padding: 120rpx 0;
}
.appointment-card {
background: #ffffff;
border-radius: 16rpx;
padding: 32rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.appointment-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
.appointment-date {
font-size: 24rpx;
color: #999;
}
.appointment-body {
padding: 24rpx 0;
border-top: 1rpx solid #f0f0f0;
border-bottom: 1rpx solid #f0f0f0;
}
.appointment-row {
display: flex;
margin-bottom: 16rpx;
}
.row-label {
font-size: 28rpx;
color: #666;
min-width: 120rpx;
}
.row-value {
font-size: 28rpx;
color: #333;
flex: 1;
}
.appointment-footer {
padding-top: 24rpx;
display: flex;
justify-content: flex-end;
}
</style>