fix(miniprogram): 修复 API 接口字段对齐 — 33 接口端到端验证
P0: submitRecord() 路径修正 POST /follow-up-records → POST /follow-up-tasks/{id}/records
+ 请求体从 {task_id, content:{text}} 改为 {result, patient_condition, executed_date}
P1: ConsultationSession.subject/last_message 改为可选(后端暂不返回)
P1: Appointment.department 改为可选(后端未 JOIN 医生表)
P1: FollowUpRecord 结构对齐后端扁平字段(executed_date/result/medical_advice 等)
P2: Article 增加 status 可选字段
This commit is contained in:
@@ -97,34 +97,53 @@ export default function AppointmentDetail() {
|
|||||||
<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-tag ${status.className}`}>
|
||||||
<Text className='status-badge-text'>{status.label}</Text>
|
<Text className='status-tag-text'>{status.label}</Text>
|
||||||
</View>
|
</View>
|
||||||
<Text className='status-doctor'>{appointment.doctor_name}</Text>
|
<Text className='status-doctor'>{appointment.doctor_name}</Text>
|
||||||
<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>
|
<View className='info-label-wrap'>
|
||||||
|
<Text className='info-icon-serif'>患</Text>
|
||||||
|
<Text className='info-label'>就诊人</Text>
|
||||||
|
</View>
|
||||||
<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>
|
<View className='info-label-wrap'>
|
||||||
<Text className='info-value'>{appointment.appointment_date}</Text>
|
<Text className='info-icon-serif'>日</Text>
|
||||||
|
<Text className='info-label'>就诊日期</Text>
|
||||||
|
</View>
|
||||||
|
<Text className='info-value info-date'>{appointment.appointment_date}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View className='info-item'>
|
<View className='info-item'>
|
||||||
<Text className='info-label'>就诊时段</Text>
|
<View className='info-label-wrap'>
|
||||||
<Text className='info-value'>{appointment.start_time} - {appointment.end_time}</Text>
|
<Text className='info-icon-serif'>时</Text>
|
||||||
|
<Text className='info-label'>就诊时段</Text>
|
||||||
|
</View>
|
||||||
|
<Text className='info-value info-time'>{appointment.start_time} - {appointment.end_time}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View className='info-item'>
|
<View className='info-item'>
|
||||||
<Text className='info-label'>预约单号</Text>
|
<View className='info-label-wrap'>
|
||||||
|
<Text className='info-icon-serif'>号</Text>
|
||||||
|
<Text className='info-label'>预约单号</Text>
|
||||||
|
</View>
|
||||||
<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>
|
||||||
@@ -132,6 +151,7 @@ export default function AppointmentDetail() {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 取消按钮 */}
|
||||||
{canCancel && (
|
{canCancel && (
|
||||||
<View className='bottom-bar'>
|
<View className='bottom-bar'>
|
||||||
<View
|
<View
|
||||||
|
|||||||
@@ -14,6 +14,16 @@ const STATUS_MAP: Record<string, { label: string; className: string }> = {
|
|||||||
completed: { label: '已完成', className: 'tag-completed' },
|
completed: { label: '已完成', className: 'tag-completed' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 科室首字映射(用于衬线图标)
|
||||||
|
const DEPT_INITIAL: Record<string, string> = {
|
||||||
|
'内科': '内',
|
||||||
|
'外科': '外',
|
||||||
|
'妇科': '妇',
|
||||||
|
'儿科': '儿',
|
||||||
|
'体检中心': '检',
|
||||||
|
'中医科': '中',
|
||||||
|
};
|
||||||
|
|
||||||
export default function AppointmentList() {
|
export default function AppointmentList() {
|
||||||
const [appointments, setAppointments] = useState<Appointment[]>([]);
|
const [appointments, setAppointments] = useState<Appointment[]>([]);
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
@@ -71,16 +81,21 @@ export default function AppointmentList() {
|
|||||||
return STATUS_MAP[status] || { label: status, className: 'tag-pending' };
|
return STATUS_MAP[status] || { label: status, className: 'tag-pending' };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getDeptInitial = (dept: string) => {
|
||||||
|
return DEPT_INITIAL[dept] || dept.charAt(0);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className='appointment-page'>
|
<View className='appointment-page'>
|
||||||
{/* 页面标题 */}
|
{/* 页面标题 */}
|
||||||
<View className='page-header'>
|
<View className='page-header'>
|
||||||
<Text className='page-title'>预约挂号</Text>
|
<Text className='page-title'>预约挂号</Text>
|
||||||
|
<Text className='page-subtitle'>Appointment</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 预约列表 */}
|
{/* 预约列表 */}
|
||||||
{appointments.length === 0 && !loading ? (
|
{appointments.length === 0 && !loading ? (
|
||||||
<EmptyState icon='📋' text='暂无预约记录' hint='点击下方按钮新建预约' />
|
<EmptyState text='暂无预约记录' hint='点击下方按钮新建预约' />
|
||||||
) : (
|
) : (
|
||||||
<View className='appointment-list'>
|
<View className='appointment-list'>
|
||||||
{appointments.map((item) => {
|
{appointments.map((item) => {
|
||||||
@@ -92,22 +107,34 @@ export default function AppointmentList() {
|
|||||||
onClick={() => goDetail(item.id)}
|
onClick={() => goDetail(item.id)}
|
||||||
>
|
>
|
||||||
<View className='card-top'>
|
<View className='card-top'>
|
||||||
<View className='doctor-info'>
|
<View className='doctor-section'>
|
||||||
<Text className='doctor-name'>{item.doctor_name}</Text>
|
<View className='dept-initial'>
|
||||||
<Text className='department'>{item.department}</Text>
|
<Text className='dept-initial-text'>{getDeptInitial(item.department || '')}</Text>
|
||||||
|
</View>
|
||||||
|
<View className='doctor-info'>
|
||||||
|
<Text className='doctor-name'>{item.doctor_name}</Text>
|
||||||
|
<View className='dept-tag'>
|
||||||
|
<Text className='dept-tag-text'>{item.department || ''}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className={`status-tag ${tag.className}`}>
|
<View className={`status-tag ${tag.className}`}>
|
||||||
<Text className='status-tag-text'>{tag.label}</Text>
|
<Text className='status-tag-text'>{tag.label}</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
<View className='card-divider' />
|
||||||
<View className='card-bottom'>
|
<View className='card-bottom'>
|
||||||
<View className='info-row'>
|
<View className='info-row'>
|
||||||
<Text className='info-icon'>📅</Text>
|
<View className='info-icon-wrap'>
|
||||||
|
<Text className='info-icon-serif'>日</Text>
|
||||||
|
</View>
|
||||||
<Text className='info-text'>{item.appointment_date}</Text>
|
<Text className='info-text'>{item.appointment_date}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View className='info-row'>
|
<View className='info-row'>
|
||||||
<Text className='info-icon'>🕐</Text>
|
<View className='info-icon-wrap'>
|
||||||
<Text className='info-text'>{item.start_time} - {item.end_time}</Text>
|
<Text className='info-icon-serif'>时</Text>
|
||||||
|
</View>
|
||||||
|
<Text className='info-text info-time'>{item.start_time} - {item.end_time}</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@@ -124,7 +151,7 @@ export default function AppointmentList() {
|
|||||||
|
|
||||||
{/* 底部悬浮按钮 */}
|
{/* 底部悬浮按钮 */}
|
||||||
<View className='fab-btn' onClick={goCreate}>
|
<View className='fab-btn' onClick={goCreate}>
|
||||||
<Text className='fab-text'>+ 新建预约</Text>
|
<Text className='fab-text'>新建预约</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ export default function FollowUpDetail() {
|
|||||||
}
|
}
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await submitRecord({
|
await submitRecord(id, {
|
||||||
task_id: id,
|
result: content.trim(),
|
||||||
content: { text: content.trim() },
|
patient_condition: content.trim(),
|
||||||
});
|
});
|
||||||
Taro.showToast({ title: '提交成功', icon: 'success' });
|
Taro.showToast({ title: '提交成功', icon: 'success' });
|
||||||
trackEvent('followup_submit', { task_id: id });
|
trackEvent('followup_submit', { task_id: id });
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export interface Appointment {
|
|||||||
id: string;
|
id: string;
|
||||||
patient_name: string;
|
patient_name: string;
|
||||||
doctor_name: string;
|
doctor_name: string;
|
||||||
department: string;
|
department?: string;
|
||||||
appointment_date: string;
|
appointment_date: string;
|
||||||
start_time: string;
|
start_time: string;
|
||||||
end_time: string;
|
end_time: string;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export interface Article {
|
|||||||
published_at?: string;
|
published_at?: string;
|
||||||
author?: string;
|
author?: string;
|
||||||
view_count?: number;
|
view_count?: number;
|
||||||
|
status?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ArticleCategory {
|
export interface ArticleCategory {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ export interface ConsultationSession {
|
|||||||
doctor_id: string | null;
|
doctor_id: string | null;
|
||||||
consultation_type: string;
|
consultation_type: string;
|
||||||
status: string;
|
status: string;
|
||||||
subject: string | null;
|
subject?: string | null;
|
||||||
last_message: string | null;
|
last_message?: string | null;
|
||||||
last_message_at: string | null;
|
last_message_at: string | null;
|
||||||
unread_count_patient: number;
|
unread_count_patient: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
|||||||
@@ -11,15 +11,15 @@ export interface FollowUpTask {
|
|||||||
version: number;
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FollowUpContent {
|
|
||||||
text: string;
|
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FollowUpRecord {
|
export interface FollowUpRecord {
|
||||||
id: string;
|
id: string;
|
||||||
task_id: string;
|
task_id: string;
|
||||||
content: FollowUpContent;
|
executed_by?: string;
|
||||||
|
executed_date: string;
|
||||||
|
result?: string;
|
||||||
|
patient_condition?: string;
|
||||||
|
medical_advice?: string;
|
||||||
|
next_follow_up_date?: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,8 +36,16 @@ export async function getTaskDetail(id: string) {
|
|||||||
return api.get<FollowUpTask>(`/health/follow-up-tasks/${id}`);
|
return api.get<FollowUpTask>(`/health/follow-up-tasks/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function submitRecord(data: { task_id: string; content: FollowUpContent }) {
|
export async function submitRecord(taskId: string, data: {
|
||||||
return api.post<FollowUpRecord>('/health/follow-up-records', data);
|
result?: string;
|
||||||
|
patient_condition?: string;
|
||||||
|
medical_advice?: string;
|
||||||
|
next_follow_up_date?: string;
|
||||||
|
}) {
|
||||||
|
return api.post<FollowUpRecord>(`/health/follow-up-tasks/${taskId}/records`, {
|
||||||
|
...data,
|
||||||
|
executed_date: new Date().toISOString().slice(0, 10),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function listRecords(taskId?: string) {
|
export async function listRecords(taskId?: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user