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 { 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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user