refactor(web): 新增 useDictionary hook + 4 个页面下拉选项改用字典 API
- 新增 useDictionary hook 支持字典 API 获取 + fallback 降级 - DoctorList 科室/职称改用 useDictionary (health_department/health_title) - FollowUpTaskList 随访类型改用 useDictionary (health_follow_up_type) - ConsultationList 咨询类型改用 useDictionary (health_consultation_type) - FamilyMembersTab 家庭关系改用 useDictionary (health_relationship)
This commit is contained in:
31
apps/web/src/hooks/useDictionary.ts
Normal file
31
apps/web/src/hooks/useDictionary.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useEffect, useState, useMemo } from 'react';
|
||||
import { listItemsByCode, type DictionaryItemInfo } from '../api/dictionaries';
|
||||
|
||||
export interface DictOption {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export function useDictionary(code: string, fallback?: DictOption[]) {
|
||||
const [items, setItems] = useState<DictionaryItemInfo[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
listItemsByCode(code)
|
||||
.then((data) => setItems(data))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setLoading(false));
|
||||
}, [code]);
|
||||
|
||||
const options = useMemo<DictOption[]>(() => {
|
||||
if (items.length > 0) {
|
||||
return items
|
||||
.sort((a, b) => a.sort_order - b.sort_order)
|
||||
.map((item) => ({ value: item.value, label: item.label }));
|
||||
}
|
||||
return fallback ?? [];
|
||||
}, [items, fallback]);
|
||||
|
||||
return { items, options, loading };
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import { PageContainer } from '../../components/PageContainer';
|
||||
import { EntityName } from '../../components/EntityName';
|
||||
import { formatDateTime } from '../../utils/format';
|
||||
import { usePaginatedData } from '../../hooks/usePaginatedData';
|
||||
import { useDictionary } from '../../hooks/useDictionary';
|
||||
|
||||
const STATUS_OPTIONS = [
|
||||
{ value: 'waiting', label: '等待中' },
|
||||
@@ -30,7 +31,7 @@ const STATUS_OPTIONS = [
|
||||
{ value: 'closed', label: '已关闭' },
|
||||
];
|
||||
|
||||
const CONSULTATION_TYPE_OPTIONS = [
|
||||
const CONSULTATION_TYPE_FALLBACK = [
|
||||
{ value: 'customer_service', label: '客服咨询' },
|
||||
{ value: 'medical', label: '医疗咨询' },
|
||||
{ value: 'health_consultation', label: '健康咨询' },
|
||||
@@ -48,6 +49,7 @@ interface ConsultationFilters {
|
||||
}
|
||||
|
||||
export default function ConsultationList() {
|
||||
const { options: CONSULTATION_TYPE_OPTIONS } = useDictionary('health_consultation_type', CONSULTATION_TYPE_FALLBACK);
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const urlPatientId = searchParams.get('patient_id');
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
DeleteOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { doctorApi, type Doctor, type CreateDoctorReq, type UpdateDoctorReq } from '../../api/health/doctors';
|
||||
import { useDictionary } from '../../hooks/useDictionary';
|
||||
import { AuthButton } from '../../components/AuthButton';
|
||||
import { PageContainer } from '../../components/PageContainer';
|
||||
import { EntityName } from '../../components/EntityName';
|
||||
@@ -27,7 +28,7 @@ import { formatDateTime } from '../../utils/format';
|
||||
import { usePaginatedData } from '../../hooks/usePaginatedData';
|
||||
|
||||
/** 科室选项 — 可后续改为从字典接口获取 */
|
||||
const DEPARTMENT_OPTIONS = [
|
||||
const DEPARTMENT_FALLBACK = [
|
||||
{ value: '全科', label: '全科' },
|
||||
{ value: '内科', label: '内科' },
|
||||
{ value: '外科', label: '外科' },
|
||||
@@ -41,7 +42,7 @@ const DEPARTMENT_OPTIONS = [
|
||||
{ value: '体检中心', label: '体检中心' },
|
||||
];
|
||||
|
||||
const TITLE_OPTIONS = [
|
||||
const TITLE_FALLBACK = [
|
||||
{ value: '住院医师', label: '住院医师' },
|
||||
{ value: '主治医师', label: '主治医师' },
|
||||
{ value: '副主任医师', label: '副主任医师' },
|
||||
@@ -74,6 +75,8 @@ interface DoctorFilters {
|
||||
}
|
||||
|
||||
export default function DoctorList() {
|
||||
const { options: DEPARTMENT_OPTIONS } = useDictionary('health_department', DEPARTMENT_FALLBACK);
|
||||
const { options: TITLE_OPTIONS } = useDictionary('health_title', TITLE_FALLBACK);
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<Doctor | null>(null);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
@@ -25,6 +25,7 @@ import { DrawerForm } from '../../components/DrawerForm';
|
||||
import { formatDate, formatDateTime } from '../../utils/format';
|
||||
import { usePaginatedData } from '../../hooks/usePaginatedData';
|
||||
import { useApiRequest } from '../../hooks/useApiRequest';
|
||||
import { useDictionary } from '../../hooks/useDictionary';
|
||||
|
||||
const STATUS_OPTIONS = [
|
||||
{ value: 'pending', label: '待处理' },
|
||||
@@ -34,7 +35,7 @@ const STATUS_OPTIONS = [
|
||||
{ value: 'cancelled', label: '已取消' },
|
||||
];
|
||||
|
||||
const FOLLOW_UP_TYPE_OPTIONS = [
|
||||
const FOLLOW_UP_TYPE_FALLBACK = [
|
||||
{ value: 'phone', label: '电话' },
|
||||
{ value: 'outpatient', label: '门诊' },
|
||||
{ value: 'home_visit', label: '家访' },
|
||||
@@ -62,6 +63,7 @@ interface AssignFormValues {
|
||||
}
|
||||
|
||||
export default function FollowUpTaskList() {
|
||||
const { options: FOLLOW_UP_TYPE_OPTIONS } = useDictionary('health_follow_up_type', FOLLOW_UP_TYPE_FALLBACK);
|
||||
const [searchParams] = useSearchParams();
|
||||
const urlPatientId = searchParams.get('patient_id');
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@ import { Table, Button, Form, Input, Select, Drawer, message, Popconfirm, Space
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { patientApi, type FamilyMember, type CreateFamilyMemberReq } from '../../../api/health/patients';
|
||||
import { AuthButton } from '../../../components/AuthButton';
|
||||
import { useDictionary } from '../../../hooks/useDictionary';
|
||||
|
||||
const RELATIONSHIP_OPTIONS = [
|
||||
const RELATIONSHIP_FALLBACK = [
|
||||
{ label: '父母', value: 'parent' },
|
||||
{ label: '配偶', value: 'spouse' },
|
||||
{ label: '子女', value: 'child' },
|
||||
@@ -17,6 +18,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export function FamilyMembersTab({ patientId }: Props) {
|
||||
const { options: RELATIONSHIP_OPTIONS } = useDictionary('health_relationship', RELATIONSHIP_FALLBACK);
|
||||
const [members, setMembers] = useState<FamilyMember[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
|
||||
Reference in New Issue
Block a user