添加接口

This commit is contained in:
xianyi
2026-01-14 10:56:00 +08:00
parent 88834825f8
commit 33d44c9728
7 changed files with 106 additions and 80 deletions

View File

@@ -70,6 +70,10 @@ import type {
ReportSendInfoResponse, ReportSendInfoResponse,
InputExpressContact, InputExpressContact,
ReportSendAddressSaveResponse, ReportSendAddressSaveResponse,
InputExamOptionalItemList,
OptionalItemInfoListResponse,
InputOptionalPackageRemove,
OptionalPackageRemoveResponse,
} from './types'; } from './types';
/** /**
@@ -550,3 +554,26 @@ export const getTijianPdfFile = (
).then(res => res.data); ).then(res => res.data);
}; };
/**
* 通过身份证号获取体检选项项目列表
*/
export const getExamOptionalItemList = (
data: InputExamOptionalItemList
): Promise<OptionalItemInfoListResponse> => {
return request.post<OptionalItemInfoListResponse>(
`${MEDICAL_EXAM_BASE_PATH}/optional-item-list`,
data
).then(res => res.data);
};
/**
* 移除弃选体检套餐选项
*/
export const removeOptionalPackage = (
data: InputOptionalPackageRemove
): Promise<OptionalPackageRemoveResponse> => {
return request.post<OptionalPackageRemoveResponse>(
`${MEDICAL_EXAM_BASE_PATH}/optional-item-remove`,
data
).then(res => res.data);
};

View File

@@ -1254,3 +1254,78 @@ export interface OutputTijianPdfFileInfo {
*/ */
export type TijianPdfFileGetResponse = CommonActionResult<OutputTijianPdfFileInfo[]>; export type TijianPdfFileGetResponse = CommonActionResult<OutputTijianPdfFileInfo[]>;
/**
* 通过身份证号获取体检选项项目列表入参
*/
export interface InputExamOptionalItemList {
/** 体检ID */
physical_exam_id: number;
}
/**
* 自助机体检套餐信息
*/
export interface PoPhysicalExamPackageInfo {
/** 体检ID */
physical_exam_id?: number | null;
/** 是否可选套餐1-是 0-否) */
is_optional_package?: number | null;
/** 是否可选套餐名称 */
is_optional_package_name?: string | null;
/** 套餐代码 */
package_code?: number | null;
/** 套餐名称 */
package_name?: string | null;
/** 登记时间 */
registration_time?: string | null;
}
/**
* 自助机体检可选项目列表出参
*/
export interface OutputPhysicalExamItemInfo {
/** 组合名称 */
combination_name?: string | null;
/** 组合代码 */
combination_code?: number | null;
/** 套餐代码 */
package_code?: number | null;
}
/**
* 自助机体检项目列表出参
*/
export interface OutputOptionalItemInfoList {
/** 套餐信息 */
packageInfo?: PoPhysicalExamPackageInfo | null;
/** 可选套餐项目列表 */
listOptionalItem?: OutputPhysicalExamItemInfo[] | null;
}
/**
* 通过身份证号获取体检选项项目列表响应
*/
export type OptionalItemInfoListResponse = CommonActionResult<OutputOptionalItemInfoList>;
/**
* 移除弃选体检套餐选项入参
*/
export interface InputOptionalPackageRemove {
/** 体检ID */
physical_exam_id: number;
/** 组合代码多个项目以逗号分割例如123,456 */
combination_code_ids: string;
}
/**
* 移除弃选体检套餐选项出参
*/
export interface OutputOptionalPackageRemove {
/** 是否成功1-成功 0-失败) */
is_success?: number | null;
}
/**
* 移除弃选体检套餐选项响应
*/
export type OptionalPackageRemoveResponse = CommonActionResult<OutputOptionalPackageRemove>;

View File

@@ -3,7 +3,6 @@ import { useEffect, useState } from 'react';
import type { ExamClient, ExamModalTab } from '../../data/mockData'; import type { ExamClient, ExamModalTab } from '../../data/mockData';
import type { CustomerAppointmentInfo, CustomerExamAddItem, CustomerInfo, PhysicalExamProgressItem } from '../../api'; import type { CustomerAppointmentInfo, CustomerExamAddItem, CustomerInfo, PhysicalExamProgressItem } from '../../api';
import { getCustomerDetail, getPhysicalExamProgress } from '../../api'; import { getCustomerDetail, getPhysicalExamProgress } from '../../api';
import { isExamActionDone } from '../../utils/examActions';
import { ExamDetailPanel } from './ExamDetailPanel'; import { ExamDetailPanel } from './ExamDetailPanel';
import { ExamAddonPanel } from './ExamAddonPanel'; import { ExamAddonPanel } from './ExamAddonPanel';
import { ExamPrintPanel } from './ExamPrintPanel'; import { ExamPrintPanel } from './ExamPrintPanel';
@@ -26,13 +25,9 @@ export const ExamModal = ({ client, tab, onTabChange, onClose }: ExamModalProps)
{ key: 'delivery', label: '报告寄送' }, { key: 'delivery', label: '报告寄送' },
]; ];
// 检查操作是否已完成(与 ExamSection 中的逻辑保持一致) const signDone = ((client as any).is_sign_in === 1) || client.signStatus === '已签到' || client.checkedItems.includes('签到');
const idCardSignInDone = isExamActionDone(client.id, 'idCardSignIn');
const printSignDone = isExamActionDone(client.id, 'printSign');
const signDone = ((client as any).is_sign_in === 1) || idCardSignInDone || client.signStatus === '已签到' || client.checkedItems.includes('签到');
const addonDone = (client.addonCount || 0) > 0; const addonDone = (client.addonCount || 0) > 0;
const printDone = printSignDone || !!client.guidePrinted; const printDone = !!client.guidePrinted;
const deliveryDone = !!client.deliveryDone; const deliveryDone = !!client.deliveryDone;
const tabDone: Record<ExamModalTab, boolean> = { const tabDone: Record<ExamModalTab, boolean> = {

View File

@@ -2,7 +2,6 @@ import { useEffect, useState, useRef } from 'react';
import type { ExamClient, ExamModalTab } from '../../data/mockData'; import type { ExamClient, ExamModalTab } from '../../data/mockData';
import { EXAM_TAGS } from '../../data/mockData'; import { EXAM_TAGS } from '../../data/mockData';
import { getTodayExamProgress } from '../../api'; import { getTodayExamProgress } from '../../api';
import { isExamActionDone } from '../../utils/examActions';
import { Badge, Button, Card, CardContent, CardHeader, InfoCard, Input } from '../ui'; import { Badge, Button, Card, CardContent, CardHeader, InfoCard, Input } from '../ui';
import { cls } from '../../utils/cls'; import { cls } from '../../utils/cls';
@@ -215,13 +214,7 @@ export const ExamSection = ({
<> <>
<div className='grid grid-cols-3 gap-3 text-sm'> <div className='grid grid-cols-3 gap-3 text-sm'>
{displayedClients.map((client) => { {displayedClients.map((client) => {
// 检查操作记录:优先使用 localStorage 记录,如果没有则使用原有逻辑
const idCardSignInDone = isExamActionDone(client.id, 'idCardSignIn');
const printSignDone = isExamActionDone(client.id, 'printSign');
const signDone = idCardSignInDone || client.signStatus === '已签到' || client.checkedItems.includes('签到');
const addonCount = client.addonCount || 0; const addonCount = client.addonCount || 0;
const printDone = printSignDone || !!client.guidePrinted;
const openModal = (tab: ExamModalTab) => onOpenModal(client.id, tab); const openModal = (tab: ExamModalTab) => onOpenModal(client.id, tab);
@@ -267,7 +260,7 @@ export const ExamSection = ({
}} }}
> >
<span></span> <span></span>
{((client as any).is_sign_in === 1) && <span></span>} {client.signStatus === '已签到' && <span></span>}
</button> </button>
<button <button
type='button' type='button'

View File

@@ -37,7 +37,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const fileInputRef = useRef<HTMLInputElement | null>(null); const fileInputRef = useRef<HTMLInputElement | null>(null);
const [consentList, setConsentList] = useState<OutputTongyishuFileInfo[]>([]); const [consentList, setConsentList] = useState<OutputTongyishuFileInfo[]>([]);
const [consentLoading, setConsentLoading] = useState(false); const [consentLoading, setConsentLoading] = useState(false);
const [consentMessage, setConsentMessage] = useState<string | null>(null);
const [previewPdf, setPreviewPdf] = useState<OutputTongyishuFileInfo | null>(null); const [previewPdf, setPreviewPdf] = useState<OutputTongyishuFileInfo | null>(null);
const [showSignature, setShowSignature] = useState(false); const [showSignature, setShowSignature] = useState(false);
const signaturePadRef = useRef<SignaturePadHandle | null>(null); const signaturePadRef = useRef<SignaturePadHandle | null>(null);
@@ -60,8 +59,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const [showDaojiandanPreview, setShowDaojiandanPreview] = useState(false); const [showDaojiandanPreview, setShowDaojiandanPreview] = useState(false);
const [daojiandanPdfData, setDaojiandanPdfData] = useState<ArrayBuffer | null>(null); const [daojiandanPdfData, setDaojiandanPdfData] = useState<ArrayBuffer | null>(null);
const [daojiandanPdfLoading, setDaojiandanPdfLoading] = useState(false); const [daojiandanPdfLoading, setDaojiandanPdfLoading] = useState(false);
const [daojiandanPdfReady, setDaojiandanPdfReady] = useState(false);
const [daojiandanPdfBlobUrl, setDaojiandanPdfBlobUrl] = useState<string | null>(null);
const daojiandanCanvasContainerRef = useRef<HTMLDivElement>(null); const daojiandanCanvasContainerRef = useRef<HTMLDivElement>(null);
const [showAddItemBillPreview, setShowAddItemBillPreview] = useState(false); const [showAddItemBillPreview, setShowAddItemBillPreview] = useState(false);
const [showAddItemBillSignature, setShowAddItemBillSignature] = useState(false); const [showAddItemBillSignature, setShowAddItemBillSignature] = useState(false);
@@ -81,8 +78,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const [currentAddItemBill, setCurrentAddItemBill] = useState<AddItemBillItem | null>(null); const [currentAddItemBill, setCurrentAddItemBill] = useState<AddItemBillItem | null>(null);
const [addItemBillPdfData, setAddItemBillPdfData] = useState<ArrayBuffer | null>(null); const [addItemBillPdfData, setAddItemBillPdfData] = useState<ArrayBuffer | null>(null);
const [addItemBillPdfLoading, setAddItemBillPdfLoading] = useState(false); const [addItemBillPdfLoading, setAddItemBillPdfLoading] = useState(false);
const [addItemBillPdfReady, setAddItemBillPdfReady] = useState(false);
const [addItemBillPdfBlobUrl, setAddItemBillPdfBlobUrl] = useState<string | null>(null);
const [batchPrintLoading, setBatchPrintLoading] = useState(false); const [batchPrintLoading, setBatchPrintLoading] = useState(false);
const addItemBillCanvasContainerRef = useRef<HTMLDivElement>(null); const addItemBillCanvasContainerRef = useRef<HTMLDivElement>(null);
@@ -96,7 +91,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const refreshTijianPdfs = async (examIdValue: number) => { const refreshTijianPdfs = async (examIdValue: number) => {
setConsentLoading(true); setConsentLoading(true);
setConsentMessage(null);
try { try {
const res = await getTijianPdfFile({ exam_id: examIdValue }); const res = await getTijianPdfFile({ exam_id: examIdValue });
@@ -120,10 +114,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
.filter((n) => Number.isFinite(n)) || []; .filter((n) => Number.isFinite(n)) || [];
setSignedCombinationCodes(signedCodes); setSignedCombinationCodes(signedCodes);
if (!mappedConsent.length) {
setConsentMessage(res.Message || '暂无知情同意书');
}
// 导检单pdf_type = 1取第一条 // 导检单pdf_type = 1取第一条
const daojiandan = list.find((item) => item.pdf_type === 1); const daojiandan = list.find((item) => item.pdf_type === 1);
if (daojiandan) { if (daojiandan) {
@@ -159,7 +149,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
} }
} catch (err) { } catch (err) {
console.error('获取体检PDF列表失败', err); console.error('获取体检PDF列表失败', err);
setConsentMessage('知情同意书加载失败,请稍后重试');
} finally { } finally {
setConsentLoading(false); setConsentLoading(false);
} }
@@ -169,7 +158,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
useEffect(() => { useEffect(() => {
if (!examId) { if (!examId) {
setConsentList([]); setConsentList([]);
setConsentMessage('缺少体检ID无法获取知情同意书');
setDaojiandanUrl(null); setDaojiandanUrl(null);
setIsDaojiandanSigned(false); setIsDaojiandanSigned(false);
return; return;
@@ -187,9 +175,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
combination_code: item.combination_code ?? null, combination_code: item.combination_code ?? null,
})); }));
setConsentList(mappedConsent); setConsentList(mappedConsent);
if (mappedConsent.length === 0) {
setConsentMessage(res.Message || '暂无知情同意书');
}
} }
} catch (err) { } catch (err) {
console.error('获取知情同意书失败', err); console.error('获取知情同意书失败', err);
@@ -452,13 +437,10 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
useEffect(() => { useEffect(() => {
if (!showDaojiandanPreview || !daojiandanUrl) { if (!showDaojiandanPreview || !daojiandanUrl) {
setDaojiandanPdfData(null); setDaojiandanPdfData(null);
setDaojiandanPdfBlobUrl(null);
setDaojiandanPdfReady(false);
return; return;
} }
let objectUrl: string | null = null; let objectUrl: string | null = null;
setDaojiandanPdfReady(false);
setDaojiandanPdfLoading(true); setDaojiandanPdfLoading(true);
setDaojiandanPdfData(null); setDaojiandanPdfData(null);
@@ -469,7 +451,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
}) })
.then((blob) => { .then((blob) => {
objectUrl = URL.createObjectURL(blob); objectUrl = URL.createObjectURL(blob);
setDaojiandanPdfBlobUrl(objectUrl);
return blob.arrayBuffer(); return blob.arrayBuffer();
}) })
.then((arrayBuffer) => { .then((arrayBuffer) => {
@@ -478,7 +459,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
}) })
.catch((err) => { .catch((err) => {
console.error('导检单PDF 拉取失败', err); console.error('导检单PDF 拉取失败', err);
setDaojiandanPdfLoading(false);
}); });
return () => { return () => {
@@ -492,8 +472,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
useEffect(() => { useEffect(() => {
if (!daojiandanPdfData || !daojiandanCanvasContainerRef.current) return; if (!daojiandanPdfData || !daojiandanCanvasContainerRef.current) return;
setDaojiandanPdfReady(false);
const renderAllPages = async () => { const renderAllPages = async () => {
try { try {
const pdf = await pdfjsLib.getDocument({ data: daojiandanPdfData }).promise; const pdf = await pdfjsLib.getDocument({ data: daojiandanPdfData }).promise;
@@ -532,10 +510,8 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
await page.render(renderContext).promise; await page.render(renderContext).promise;
} }
setDaojiandanPdfReady(true);
} catch (err) { } catch (err) {
console.error('导检单PDF 渲染失败', err); console.error('导检单PDF 渲染失败', err);
setDaojiandanPdfLoading(false);
} }
}; };
@@ -546,13 +522,10 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
useEffect(() => { useEffect(() => {
if (!showAddItemBillPreview || !currentAddItemBill?.pdf_url) { if (!showAddItemBillPreview || !currentAddItemBill?.pdf_url) {
setAddItemBillPdfData(null); setAddItemBillPdfData(null);
setAddItemBillPdfBlobUrl(null);
setAddItemBillPdfReady(false);
return; return;
} }
let objectUrl: string | null = null; let objectUrl: string | null = null;
setAddItemBillPdfReady(false);
setAddItemBillPdfLoading(true); setAddItemBillPdfLoading(true);
setAddItemBillPdfData(null); setAddItemBillPdfData(null);
@@ -563,16 +536,13 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
}) })
.then((blob) => { .then((blob) => {
objectUrl = URL.createObjectURL(blob); objectUrl = URL.createObjectURL(blob);
setAddItemBillPdfBlobUrl(objectUrl);
return blob.arrayBuffer(); return blob.arrayBuffer();
}) })
.then((arrayBuffer) => { .then((arrayBuffer) => {
setAddItemBillPdfData(arrayBuffer); setAddItemBillPdfData(arrayBuffer);
setAddItemBillPdfLoading(false);
}) })
.catch((err) => { .catch((err) => {
console.error('加项单PDF 拉取失败', err); console.error('加项单PDF 拉取失败', err);
setAddItemBillPdfLoading(false);
}); });
return () => { return () => {
@@ -586,8 +556,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
useEffect(() => { useEffect(() => {
if (!addItemBillPdfData || !addItemBillCanvasContainerRef.current) return; if (!addItemBillPdfData || !addItemBillCanvasContainerRef.current) return;
setAddItemBillPdfReady(false);
const renderAllPages = async () => { const renderAllPages = async () => {
try { try {
const pdf = await pdfjsLib.getDocument({ data: addItemBillPdfData }).promise; const pdf = await pdfjsLib.getDocument({ data: addItemBillPdfData }).promise;
@@ -626,10 +594,8 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
await page.render(renderContext).promise; await page.render(renderContext).promise;
} }
setAddItemBillPdfReady(true);
} catch (err) { } catch (err) {
console.error('加项单PDF 渲染失败', err); console.error('加项单PDF 渲染失败', err);
setAddItemBillPdfLoading(false);
} }
}; };
@@ -645,7 +611,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const renderDaojiandan = async () => { const renderDaojiandan = async () => {
try { try {
setDaojiandanPdfLoading(true);
container.innerHTML = ''; container.innerHTML = '';
const resp = await fetch(daojiandanUrl); const resp = await fetch(daojiandanUrl);
@@ -687,7 +652,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
console.error('导检单PDF 渲染失败', err); console.error('导检单PDF 渲染失败', err);
} finally { } finally {
if (!cancelled) { if (!cancelled) {
setDaojiandanPdfLoading(false);
} }
} }
}; };
@@ -1015,7 +979,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
if (res.Status === 200 && res.Data?.pdf_url) { if (res.Status === 200 && res.Data?.pdf_url) {
setDaojiandanSubmitMessage('签名提交成功'); setDaojiandanSubmitMessage('签名提交成功');
const pdfUrlValue = res.Data.pdf_url; const pdfUrlValue = res.Data.pdf_url;
const pdfNameValue = res.Data.pdf_name || '导检单';
setDaojiandanUrl(pdfUrlValue); setDaojiandanUrl(pdfUrlValue);
setIsDaojiandanSigned(true); // 签名成功后标记为已签名 setIsDaojiandanSigned(true); // 签名成功后标记为已签名

View File

@@ -7,7 +7,7 @@ interface TopBarProps {
onLoginClick?: () => void; onLoginClick?: () => void;
} }
export const TopBar = ({ search, onSearch, enableSearch = true, operatorName, onLoginClick }: TopBarProps) => ( export const TopBar = ({ enableSearch = true, operatorName, onLoginClick }: TopBarProps) => (
<header className='flex items-center gap-3 p-2 border-b bg-white'> <header className='flex items-center gap-3 p-2 border-b bg-white'>
<div className='flex-1 flex items-center gap-3'> <div className='flex-1 flex items-center gap-3'>
{enableSearch ? ( {enableSearch ? (

View File

@@ -36,30 +36,3 @@ export interface ExamActionRecord {
/** 记录时间戳 */ /** 记录时间戳 */
timestamp?: string; timestamp?: string;
} }
/**
* 获取操作记录
*/
export const getExamActionRecord = (_examId: string | number): ExamActionRecord | null => {
// 已废弃,不再从本地存储读取
return null;
};
/**
* 设置操作记录
*/
export const setExamActionRecord = (
examId: string | number,
action: keyof ExamActionRecord,
value: boolean = true
): void => {
// 已废弃,不再写入本地存储
};
/**
* 检查操作是否已完成
*/
export const isExamActionDone = (examId: string | number, action: keyof ExamActionRecord): boolean => {
// 已废弃,统一由实时数据决定
return false;
};