138 lines
4.3 KiB
TypeScript
138 lines
4.3 KiB
TypeScript
import { useEffect, useMemo, useState } from 'react';
|
|
import { useOutletContext } from 'react-router-dom';
|
|
|
|
import type { ExamClient, ExamModalTab } from '../data/mockData';
|
|
import { EXAM_TAGS } from '../data/mockData';
|
|
import { ExamSection } from '../components/exam/ExamSection';
|
|
import { ExamModal } from '../components/exam/ExamModal';
|
|
import type { MainLayoutContext } from '../layouts/MainLayout';
|
|
import { getPhysicalExamCustomerList } from '../api';
|
|
|
|
export const ExamPage = () => {
|
|
const { search } = useOutletContext<MainLayoutContext>();
|
|
const [clients, setClients] = useState<ExamClient[]>([]);
|
|
const [examSelectedId, setExamSelectedId] = useState<string>('');
|
|
const [examPanelTab, setExamPanelTab] = useState<ExamModalTab>('detail');
|
|
const [examModalOpen, setExamModalOpen] = useState(false);
|
|
const [examFilterTag, setExamFilterTag] = useState<(typeof EXAM_TAGS)[number]>('全部');
|
|
|
|
// 将筛选标签映射为接口 filter_type
|
|
const filterType = useMemo(() => {
|
|
switch (examFilterTag) {
|
|
case '上午':
|
|
return 2;
|
|
case '下午':
|
|
return 3;
|
|
case '高客':
|
|
return 4;
|
|
case '普客':
|
|
return 5;
|
|
case '已登记':
|
|
return 6;
|
|
case '未登记':
|
|
return 7;
|
|
case '散客':
|
|
return 8;
|
|
case '团客':
|
|
return 9;
|
|
default:
|
|
return 1; // 全部
|
|
}
|
|
}, [examFilterTag]);
|
|
|
|
// 从接口拉取体检客户列表
|
|
useEffect(() => {
|
|
const payload = {
|
|
customer_name: search.trim() || undefined,
|
|
phone: undefined,
|
|
id_no: undefined,
|
|
filter_type: filterType,
|
|
};
|
|
getPhysicalExamCustomerList(payload)
|
|
.then((res) => {
|
|
const list = res.Data || [];
|
|
const mapped: ExamClient[] = list.map((item) => {
|
|
// 状态映射到联合类型
|
|
const status: ExamClient['status'] =
|
|
item.is_sign_in === 1
|
|
? '已签到'
|
|
: (item.physical_exam_status_name ?? '').includes('餐')
|
|
? '用餐'
|
|
: '体检中';
|
|
|
|
const signStatus: ExamClient['signStatus'] = item.is_register === 1 ? '已登记' : '未登记';
|
|
const customerType: ExamClient['customerType'] = item.customer_type === 1 ? '团客' : '散客';
|
|
const vipType: ExamClient['vipType'] = item.is_vip === 1 ? '高客' : '普客';
|
|
|
|
// 粗略判断上午/下午
|
|
const timeSlot: ExamClient['timeSlot'] =
|
|
(item.physical_exam_time || '').includes('下午') ? '下午' : '上午';
|
|
|
|
return {
|
|
id: String(item.physical_exam_id ?? ''),
|
|
name: item.customer_name || '未知客户',
|
|
gender: '男', // 后端未提供,默认填充
|
|
age: 0,
|
|
level: item.member_level || (item.is_vip === 1 ? 'VIP' : '普通'),
|
|
packageName: item.package_name || '未提供套餐',
|
|
status,
|
|
elapsed: '',
|
|
checkedItems: [],
|
|
pendingItems: [],
|
|
timeSlot,
|
|
vipType,
|
|
signStatus,
|
|
customerType,
|
|
guidePrinted: item.is_print === 1,
|
|
addonCount: item.add_item_count ?? 0,
|
|
};
|
|
});
|
|
setClients(mapped);
|
|
if (mapped.length && !examSelectedId) {
|
|
setExamSelectedId(mapped[0].id);
|
|
} else if (mapped.length === 0) {
|
|
setExamSelectedId('');
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
console.error('获取体检客户列表失败', err);
|
|
});
|
|
}, [search, filterType, examSelectedId]);
|
|
|
|
const selectedExamClient: ExamClient | undefined = useMemo(
|
|
() => clients.find((c) => c.id === examSelectedId) || clients[0],
|
|
[clients, examSelectedId],
|
|
);
|
|
|
|
const handleOpenModal = (id: string, tab: ExamModalTab) => {
|
|
setExamSelectedId(id);
|
|
setExamPanelTab(tab);
|
|
setExamModalOpen(true);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{selectedExamClient && (
|
|
<ExamSection
|
|
filteredClients={clients}
|
|
selectedExamClient={selectedExamClient}
|
|
examFilterTag={examFilterTag}
|
|
onFilterChange={setExamFilterTag}
|
|
onOpenModal={handleOpenModal}
|
|
/>
|
|
)}
|
|
|
|
{examModalOpen && (
|
|
<ExamModal
|
|
client={selectedExamClient}
|
|
tab={examPanelTab}
|
|
onTabChange={setExamPanelTab}
|
|
onClose={() => setExamModalOpen(false)}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
|