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

View File

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