fix(miniprogram): 预约详情/随访详情改为 API 获取数据,移除 Storage 缓存传递

This commit is contained in:
iven
2026-04-24 12:24:49 +08:00
parent 2dc280a401
commit f75bc191e6
4 changed files with 61 additions and 47 deletions

View File

@@ -1,8 +1,10 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { View, Text } from '@tarojs/components';
import Taro, { useRouter } from '@tarojs/taro';
import { cancelAppointment } from '../../../services/appointment';
import { getAppointment, cancelAppointment } from '../../../services/appointment';
import type { Appointment } from '../../../services/appointment';
import Loading from '../../../components/Loading';
import ErrorState from '../../../components/ErrorState';
import './index.scss';
const STATUS_MAP: Record<string, { label: string; className: string }> = {
@@ -15,13 +17,27 @@ const STATUS_MAP: Record<string, { label: string; className: string }> = {
export default function AppointmentDetail() {
const router = useRouter();
const id = router.params.id || '';
const [appointment, setAppointment] = useState<Appointment | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const [cancelling, setCancelling] = useState(false);
// 从缓存获取预约数据
const cached = Taro.getStorageSync('appointment_detail_cache');
const appointment: Appointment | null = (cached && cached.id === id) ? cached : null;
useEffect(() => {
if (!id) return;
setLoading(true);
getAppointment(id)
.then((data) => setAppointment(data))
.catch((err) => {
console.error('[AppointmentDetail]', err);
setError(true);
})
.finally(() => setLoading(false));
}, [id]);
const status = appointment ? (STATUS_MAP[appointment.status] || { label: appointment.status, className: 'tag-pending' }) : { label: '未知', className: 'tag-pending' };
const status = appointment
? (STATUS_MAP[appointment.status] || { label: appointment.status, className: 'tag-pending' })
: { label: '未知', className: 'tag-pending' };
const canCancel = appointment && (appointment.status === 'pending' || appointment.status === 'confirmed');
const handleCancel = async () => {
@@ -37,9 +53,7 @@ export default function AppointmentDetail() {
try {
await cancelAppointment(appointment.id, appointment.version);
Taro.showToast({ title: '已取消预约', icon: 'success' });
setTimeout(() => {
Taro.navigateBack();
}, 1500);
setTimeout(() => Taro.navigateBack(), 1500);
} catch {
Taro.showToast({ title: '取消失败', icon: 'none' });
} finally {
@@ -47,41 +61,42 @@ export default function AppointmentDetail() {
}
};
const goBack = () => {
Taro.navigateBack();
};
const goBack = () => Taro.navigateBack();
if (!appointment) {
if (loading) {
return (
<View className='detail-page'>
<View className='detail-header'>
<View className='back-btn' onClick={goBack}>
<Text className='back-text'></Text>
</View>
<View className='back-btn' onClick={goBack}><Text className='back-text'></Text></View>
<Text className='header-title'></Text>
<View className='header-placeholder' />
</View>
<View className='empty-state'>
<Text className='empty-icon'>📋</Text>
<Text className='empty-text'></Text>
<Text className='empty-hint'></Text>
<Loading />
</View>
);
}
if (error || !appointment) {
return (
<View className='detail-page'>
<View className='detail-header'>
<View className='back-btn' onClick={goBack}><Text className='back-text'></Text></View>
<Text className='header-title'></Text>
<View className='header-placeholder' />
</View>
<ErrorState message='未找到预约信息' />
</View>
);
}
return (
<View className='detail-page'>
{/* 顶部导航 */}
<View className='detail-header'>
<View className='back-btn' onClick={goBack}>
<Text className='back-text'></Text>
</View>
<View className='back-btn' onClick={goBack}><Text className='back-text'></Text></View>
<Text className='header-title'></Text>
<View className='header-placeholder' />
</View>
{/* 状态卡片 */}
<View className='status-card'>
<View className={`status-badge ${status.className}`}>
<Text className='status-badge-text'>{status.label}</Text>
@@ -90,32 +105,26 @@ export default function AppointmentDetail() {
<Text className='status-dept'>{appointment.department}</Text>
</View>
{/* 详情信息 */}
<View className='info-section'>
<Text className='section-title'></Text>
<View className='info-item'>
<Text className='info-label'></Text>
<Text className='info-value'>{appointment.patient_name}</Text>
</View>
<View className='info-item'>
<Text className='info-label'></Text>
<Text className='info-value'>{appointment.appointment_date}</Text>
</View>
<View className='info-item'>
<Text className='info-label'></Text>
<Text className='info-value'>{appointment.time_slot}</Text>
</View>
<View className='info-item'>
<Text className='info-label'></Text>
<Text className='info-value info-id'>{appointment.id}</Text>
</View>
</View>
{/* 温馨提示 */}
{(appointment.status === 'pending' || appointment.status === 'confirmed') && (
<View className='tips-card'>
<Text className='tips-title'></Text>
@@ -123,7 +132,6 @@ export default function AppointmentDetail() {
</View>
)}
{/* 底部操作 */}
{canCancel && (
<View className='bottom-bar'>
<View

View File

@@ -1,7 +1,10 @@
import React, { useState, useEffect } from 'react';
import { View, Text, Textarea } from '@tarojs/components';
import Taro, { useRouter } from '@tarojs/taro';
import { listTasks, submitRecord, FollowUpTask } from '../../../services/followup';
import { getTaskDetail, submitRecord } from '../../../services/followup';
import type { FollowUpTask } from '../../../services/followup';
import Loading from '../../../components/Loading';
import ErrorState from '../../../components/ErrorState';
import './index.scss';
export default function FollowUpDetail() {
@@ -12,16 +15,17 @@ export default function FollowUpDetail() {
const [content, setContent] = useState('');
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
useEffect(() => {
if (!id) return;
setLoading(true);
listTasks()
.then((res) => {
const found = (res.data || []).find((t) => t.id === id);
setTask(found || null);
getTaskDetail(id)
.then((data) => setTask(data))
.catch((err) => {
console.error('[FollowUpDetail]', err);
setError(true);
})
.catch(() => Taro.showToast({ title: '加载失败', icon: 'none' }))
.finally(() => setLoading(false));
}, [id]);
@@ -54,19 +58,15 @@ export default function FollowUpDetail() {
if (loading) {
return (
<View className='detail-page'>
<View className='loading-state'>
<Text className='loading-text'>...</Text>
</View>
<Loading />
</View>
);
}
if (!task) {
if (error || !task) {
return (
<View className='detail-page'>
<View className='empty-state'>
<Text className='empty-text'></Text>
</View>
<ErrorState message='任务不存在' />
</View>
);
}
@@ -75,7 +75,6 @@ export default function FollowUpDetail() {
return (
<View className='detail-page'>
{/* 任务详情 */}
<View className='detail-card'>
<Text className='detail-title'>{task.task_type}</Text>
<View className='detail-row'>
@@ -93,7 +92,6 @@ export default function FollowUpDetail() {
)}
</View>
{/* 提交表单 */}
{!isCompleted && (
<View className='submit-card'>
<Text className='section-title'>访</Text>

View File

@@ -30,6 +30,10 @@ export async function listAppointments(page = 1) {
return api.get<{ data: Appointment[]; total: number }>(`/health/appointments?page=${page}&page_size=20`);
}
export async function getAppointment(id: string) {
return api.get<Appointment>(`/health/appointments/${id}`);
}
export async function createAppointment(data: {
patient_id: string;
doctor_id: string;

View File

@@ -29,6 +29,10 @@ export async function listTasks(status?: string) {
);
}
export async function getTaskDetail(id: string) {
return api.get<FollowUpTask>(`/health/follow-up-tasks/${id}`);
}
export async function submitRecord(data: { task_id: string; content: FollowUpContent }) {
return api.post<FollowUpRecord>('/health/follow-up-records', data);
}