fix(miniprogram): 预约详情/随访详情改为 API 获取数据,移除 Storage 缓存传递
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user