feat(web): 患者快捷导航 + 列表页 URL patient_id 筛选 + AI 列表患者 Link
- 患者详情页增加快捷导航卡片(预约/咨询/透析/随访/AI) - 5 个列表页支持 URL ?patient_id=xxx 自动筛选 - AI 分析列表患者 ID 改为可点击 Link 跳转详情
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { useSearchParams, Link } from 'react-router-dom';
|
||||
import { Table, Select, Tag, Space, Button, message, Typography } from 'antd';
|
||||
import {
|
||||
RobotOutlined,
|
||||
@@ -247,12 +248,15 @@ function SuggestionPanel({ analysisId, isDark }: { analysisId: string; isDark: b
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export default function AiAnalysisList() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const urlPatientId = searchParams.get('patient_id');
|
||||
const [data, setData] = useState<AnalysisItem[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [query, setQuery] = useState<{ page: number; page_size: number; analysis_type?: string }>({
|
||||
const [query, setQuery] = useState<{ page: number; page_size: number; analysis_type?: string; patient_id?: string }>({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
patient_id: urlPatientId || undefined,
|
||||
});
|
||||
const [expandedId, setExpandedId] = useState<string | null>(null);
|
||||
const [detail, setDetail] = useState<AnalysisItem | null>(null);
|
||||
@@ -313,12 +317,14 @@ export default function AiAnalysisList() {
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '患者 ID',
|
||||
title: '患者',
|
||||
dataIndex: 'patient_id',
|
||||
key: 'patient_id',
|
||||
width: 120,
|
||||
width: 140,
|
||||
render: (v: string) => (
|
||||
<span style={{ fontFamily: 'monospace', fontSize: 12 }}>{v.slice(0, 8)}</span>
|
||||
<Link to={`/health/patients/${v}`} style={{ fontFamily: 'monospace', fontSize: 12 }}>
|
||||
{v.slice(0, 8)}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useCallback, useEffect, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import {
|
||||
Table,
|
||||
Button,
|
||||
@@ -83,6 +84,8 @@ interface AppointmentFilters {
|
||||
}
|
||||
|
||||
export default function AppointmentList() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const urlPatientId = searchParams.get('patient_id');
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
@@ -104,7 +107,7 @@ export default function AppointmentList() {
|
||||
page_size: pageSize,
|
||||
status: filters.status || undefined,
|
||||
date: dateStart === dateEnd ? dateStart : undefined,
|
||||
patient_id: undefined, // 后端暂不支持 patientSearch 文本搜索
|
||||
patient_id: urlPatientId || undefined,
|
||||
});
|
||||
},
|
||||
[],
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from 'antd';
|
||||
import { PlusOutlined, CloseCircleOutlined } from '@ant-design/icons';
|
||||
import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { consultationApi, type Session, type CreateSessionReq } from '../../api/health/consultations';
|
||||
import { StatusTag } from './components/StatusTag';
|
||||
import { PatientSelect } from './components/PatientSelect';
|
||||
@@ -49,6 +49,8 @@ interface ConsultationFilters {
|
||||
|
||||
export default function ConsultationList() {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const urlPatientId = searchParams.get('patient_id');
|
||||
|
||||
// Close session
|
||||
const [closingId, setClosingId] = useState<string | null>(null);
|
||||
@@ -63,13 +65,14 @@ export default function ConsultationList() {
|
||||
async (page: number, pageSize: number, filters: ConsultationFilters) => {
|
||||
const params: Record<string, unknown> = { page, page_size: pageSize };
|
||||
if (filters.status) params.status = filters.status;
|
||||
if (urlPatientId) params.patient_id = urlPatientId;
|
||||
if (filters.dateRange) {
|
||||
params.created_start = filters.dateRange[0];
|
||||
params.created_end = filters.dateRange[1];
|
||||
}
|
||||
return consultationApi.listSessions(params as Parameters<typeof consultationApi.listSessions>[0]);
|
||||
},
|
||||
[],
|
||||
[urlPatientId],
|
||||
);
|
||||
|
||||
const {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState, useCallback, useMemo } from 'react';
|
||||
import { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { Table, Tag, Button, Modal, Form, InputNumber, DatePicker, Select, message, Popconfirm, Space, Input } from 'antd';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined, AuditOutlined } from '@ant-design/icons';
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
@@ -27,7 +28,9 @@ interface PatientOption {
|
||||
}
|
||||
|
||||
export default function DialysisManageList() {
|
||||
const [selectedPatientId, setSelectedPatientId] = useState<string | null>(null);
|
||||
const [searchParams] = useSearchParams();
|
||||
const urlPatientId = searchParams.get('patient_id');
|
||||
const [selectedPatientId, setSelectedPatientId] = useState<string | null>(urlPatientId);
|
||||
const [patientOptions, setPatientOptions] = useState<PatientOption[]>([]);
|
||||
const [patientSearch, setPatientSearch] = useState('');
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
@@ -38,6 +41,15 @@ export default function DialysisManageList() {
|
||||
const [reviewRecord, setReviewRecord] = useState<DialysisRecord | null>(null);
|
||||
const [reviewSubmitting, setReviewSubmitting] = useState(false);
|
||||
|
||||
// URL 带了 patient_id 时预加载患者选项
|
||||
useEffect(() => {
|
||||
if (urlPatientId) {
|
||||
patientApi.get(urlPatientId).then((p) => {
|
||||
if (p) setPatientOptions([{ id: p.id, name: p.name }]);
|
||||
}).catch(() => {});
|
||||
}
|
||||
}, [urlPatientId]);
|
||||
|
||||
const searchPatients = async (keyword: string) => {
|
||||
if (!keyword.trim()) {
|
||||
setPatientOptions([]);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import {
|
||||
Table,
|
||||
Select,
|
||||
@@ -61,6 +62,9 @@ interface AssignFormValues {
|
||||
}
|
||||
|
||||
export default function FollowUpTaskList() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const urlPatientId = searchParams.get('patient_id');
|
||||
|
||||
// --- Paginated data with usePaginatedData ---
|
||||
const fetchFn = useCallback(
|
||||
async (page: number, pageSize: number, filters: FollowUpFilters) => {
|
||||
@@ -68,13 +72,14 @@ export default function FollowUpTaskList() {
|
||||
if (filters.status) params.status = filters.status;
|
||||
if (filters.followUpType) params.follow_up_type = filters.followUpType;
|
||||
if (filters.assigneeId) params.assigned_to = filters.assigneeId;
|
||||
if (urlPatientId) params.patient_id = urlPatientId;
|
||||
if (filters.dateRange) {
|
||||
params.planned_date_start = filters.dateRange[0];
|
||||
params.planned_date_end = filters.dateRange[1];
|
||||
}
|
||||
return followUpApi.listTasks(params as Parameters<typeof followUpApi.listTasks>[0]);
|
||||
},
|
||||
[],
|
||||
[urlPatientId],
|
||||
);
|
||||
|
||||
const {
|
||||
|
||||
Reference in New Issue
Block a user