添加接口
This commit is contained in:
@@ -70,6 +70,10 @@ import type {
|
||||
ReportSendInfoResponse,
|
||||
InputExpressContact,
|
||||
ReportSendAddressSaveResponse,
|
||||
InputExamOptionalItemList,
|
||||
OptionalItemInfoListResponse,
|
||||
InputOptionalPackageRemove,
|
||||
OptionalPackageRemoveResponse,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
@@ -550,3 +554,26 @@ export const getTijianPdfFile = (
|
||||
).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);
|
||||
};
|
||||
|
||||
@@ -1254,3 +1254,78 @@ export interface 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>;
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useEffect, useState } from 'react';
|
||||
import type { ExamClient, ExamModalTab } from '../../data/mockData';
|
||||
import type { CustomerAppointmentInfo, CustomerExamAddItem, CustomerInfo, PhysicalExamProgressItem } from '../../api';
|
||||
import { getCustomerDetail, getPhysicalExamProgress } from '../../api';
|
||||
import { isExamActionDone } from '../../utils/examActions';
|
||||
import { ExamDetailPanel } from './ExamDetailPanel';
|
||||
import { ExamAddonPanel } from './ExamAddonPanel';
|
||||
import { ExamPrintPanel } from './ExamPrintPanel';
|
||||
@@ -26,13 +25,9 @@ export const ExamModal = ({ client, tab, onTabChange, onClose }: ExamModalProps)
|
||||
{ key: 'delivery', label: '报告寄送' },
|
||||
];
|
||||
|
||||
// 检查操作是否已完成(与 ExamSection 中的逻辑保持一致)
|
||||
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 signDone = ((client as any).is_sign_in === 1) || client.signStatus === '已签到' || client.checkedItems.includes('签到');
|
||||
const addonDone = (client.addonCount || 0) > 0;
|
||||
const printDone = printSignDone || !!client.guidePrinted;
|
||||
const printDone = !!client.guidePrinted;
|
||||
const deliveryDone = !!client.deliveryDone;
|
||||
|
||||
const tabDone: Record<ExamModalTab, boolean> = {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useEffect, useState, useRef } from 'react';
|
||||
import type { ExamClient, ExamModalTab } from '../../data/mockData';
|
||||
import { EXAM_TAGS } from '../../data/mockData';
|
||||
import { getTodayExamProgress } from '../../api';
|
||||
import { isExamActionDone } from '../../utils/examActions';
|
||||
import { Badge, Button, Card, CardContent, CardHeader, InfoCard, Input } from '../ui';
|
||||
import { cls } from '../../utils/cls';
|
||||
|
||||
@@ -215,13 +214,7 @@ export const ExamSection = ({
|
||||
<>
|
||||
<div className='grid grid-cols-3 gap-3 text-sm'>
|
||||
{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 printDone = printSignDone || !!client.guidePrinted;
|
||||
const openModal = (tab: ExamModalTab) => onOpenModal(client.id, tab);
|
||||
|
||||
|
||||
@@ -267,7 +260,7 @@ export const ExamSection = ({
|
||||
}}
|
||||
>
|
||||
<span>签到</span>
|
||||
{((client as any).is_sign_in === 1) && <span>✅</span>}
|
||||
{client.signStatus === '已签到' && <span>✅</span>}
|
||||
</button>
|
||||
<button
|
||||
type='button'
|
||||
|
||||
@@ -37,7 +37,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
||||
const [consentList, setConsentList] = useState<OutputTongyishuFileInfo[]>([]);
|
||||
const [consentLoading, setConsentLoading] = useState(false);
|
||||
const [consentMessage, setConsentMessage] = useState<string | null>(null);
|
||||
const [previewPdf, setPreviewPdf] = useState<OutputTongyishuFileInfo | null>(null);
|
||||
const [showSignature, setShowSignature] = useState(false);
|
||||
const signaturePadRef = useRef<SignaturePadHandle | null>(null);
|
||||
@@ -60,8 +59,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
const [showDaojiandanPreview, setShowDaojiandanPreview] = useState(false);
|
||||
const [daojiandanPdfData, setDaojiandanPdfData] = useState<ArrayBuffer | null>(null);
|
||||
const [daojiandanPdfLoading, setDaojiandanPdfLoading] = useState(false);
|
||||
const [daojiandanPdfReady, setDaojiandanPdfReady] = useState(false);
|
||||
const [daojiandanPdfBlobUrl, setDaojiandanPdfBlobUrl] = useState<string | null>(null);
|
||||
const daojiandanCanvasContainerRef = useRef<HTMLDivElement>(null);
|
||||
const [showAddItemBillPreview, setShowAddItemBillPreview] = 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 [addItemBillPdfData, setAddItemBillPdfData] = useState<ArrayBuffer | null>(null);
|
||||
const [addItemBillPdfLoading, setAddItemBillPdfLoading] = useState(false);
|
||||
const [addItemBillPdfReady, setAddItemBillPdfReady] = useState(false);
|
||||
const [addItemBillPdfBlobUrl, setAddItemBillPdfBlobUrl] = useState<string | null>(null);
|
||||
const [batchPrintLoading, setBatchPrintLoading] = useState(false);
|
||||
const addItemBillCanvasContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -96,7 +91,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
|
||||
const refreshTijianPdfs = async (examIdValue: number) => {
|
||||
setConsentLoading(true);
|
||||
setConsentMessage(null);
|
||||
|
||||
try {
|
||||
const res = await getTijianPdfFile({ exam_id: examIdValue });
|
||||
@@ -120,10 +114,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
.filter((n) => Number.isFinite(n)) || [];
|
||||
setSignedCombinationCodes(signedCodes);
|
||||
|
||||
if (!mappedConsent.length) {
|
||||
setConsentMessage(res.Message || '暂无知情同意书');
|
||||
}
|
||||
|
||||
// 导检单(pdf_type = 1,取第一条)
|
||||
const daojiandan = list.find((item) => item.pdf_type === 1);
|
||||
if (daojiandan) {
|
||||
@@ -159,7 +149,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取体检PDF列表失败', err);
|
||||
setConsentMessage('知情同意书加载失败,请稍后重试');
|
||||
} finally {
|
||||
setConsentLoading(false);
|
||||
}
|
||||
@@ -169,7 +158,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
useEffect(() => {
|
||||
if (!examId) {
|
||||
setConsentList([]);
|
||||
setConsentMessage('缺少体检ID,无法获取知情同意书');
|
||||
setDaojiandanUrl(null);
|
||||
setIsDaojiandanSigned(false);
|
||||
return;
|
||||
@@ -187,9 +175,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
combination_code: item.combination_code ?? null,
|
||||
}));
|
||||
setConsentList(mappedConsent);
|
||||
if (mappedConsent.length === 0) {
|
||||
setConsentMessage(res.Message || '暂无知情同意书');
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取知情同意书失败', err);
|
||||
@@ -452,13 +437,10 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
useEffect(() => {
|
||||
if (!showDaojiandanPreview || !daojiandanUrl) {
|
||||
setDaojiandanPdfData(null);
|
||||
setDaojiandanPdfBlobUrl(null);
|
||||
setDaojiandanPdfReady(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let objectUrl: string | null = null;
|
||||
setDaojiandanPdfReady(false);
|
||||
setDaojiandanPdfLoading(true);
|
||||
setDaojiandanPdfData(null);
|
||||
|
||||
@@ -469,7 +451,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
})
|
||||
.then((blob) => {
|
||||
objectUrl = URL.createObjectURL(blob);
|
||||
setDaojiandanPdfBlobUrl(objectUrl);
|
||||
return blob.arrayBuffer();
|
||||
})
|
||||
.then((arrayBuffer) => {
|
||||
@@ -478,7 +459,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('导检单PDF 拉取失败', err);
|
||||
setDaojiandanPdfLoading(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
@@ -492,8 +472,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
useEffect(() => {
|
||||
if (!daojiandanPdfData || !daojiandanCanvasContainerRef.current) return;
|
||||
|
||||
setDaojiandanPdfReady(false);
|
||||
|
||||
const renderAllPages = async () => {
|
||||
try {
|
||||
const pdf = await pdfjsLib.getDocument({ data: daojiandanPdfData }).promise;
|
||||
@@ -532,10 +510,8 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
await page.render(renderContext).promise;
|
||||
}
|
||||
|
||||
setDaojiandanPdfReady(true);
|
||||
} catch (err) {
|
||||
console.error('导检单PDF 渲染失败', err);
|
||||
setDaojiandanPdfLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -546,13 +522,10 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
useEffect(() => {
|
||||
if (!showAddItemBillPreview || !currentAddItemBill?.pdf_url) {
|
||||
setAddItemBillPdfData(null);
|
||||
setAddItemBillPdfBlobUrl(null);
|
||||
setAddItemBillPdfReady(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let objectUrl: string | null = null;
|
||||
setAddItemBillPdfReady(false);
|
||||
setAddItemBillPdfLoading(true);
|
||||
setAddItemBillPdfData(null);
|
||||
|
||||
@@ -563,16 +536,13 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
})
|
||||
.then((blob) => {
|
||||
objectUrl = URL.createObjectURL(blob);
|
||||
setAddItemBillPdfBlobUrl(objectUrl);
|
||||
return blob.arrayBuffer();
|
||||
})
|
||||
.then((arrayBuffer) => {
|
||||
setAddItemBillPdfData(arrayBuffer);
|
||||
setAddItemBillPdfLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('加项单PDF 拉取失败', err);
|
||||
setAddItemBillPdfLoading(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
@@ -586,8 +556,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
useEffect(() => {
|
||||
if (!addItemBillPdfData || !addItemBillCanvasContainerRef.current) return;
|
||||
|
||||
setAddItemBillPdfReady(false);
|
||||
|
||||
const renderAllPages = async () => {
|
||||
try {
|
||||
const pdf = await pdfjsLib.getDocument({ data: addItemBillPdfData }).promise;
|
||||
@@ -626,10 +594,8 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
await page.render(renderContext).promise;
|
||||
}
|
||||
|
||||
setAddItemBillPdfReady(true);
|
||||
} catch (err) {
|
||||
console.error('加项单PDF 渲染失败', err);
|
||||
setAddItemBillPdfLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -645,7 +611,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
|
||||
const renderDaojiandan = async () => {
|
||||
try {
|
||||
setDaojiandanPdfLoading(true);
|
||||
container.innerHTML = '';
|
||||
|
||||
const resp = await fetch(daojiandanUrl);
|
||||
@@ -687,7 +652,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
console.error('导检单PDF 渲染失败', err);
|
||||
} finally {
|
||||
if (!cancelled) {
|
||||
setDaojiandanPdfLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1015,7 +979,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
if (res.Status === 200 && res.Data?.pdf_url) {
|
||||
setDaojiandanSubmitMessage('签名提交成功');
|
||||
const pdfUrlValue = res.Data.pdf_url;
|
||||
const pdfNameValue = res.Data.pdf_name || '导检单';
|
||||
setDaojiandanUrl(pdfUrlValue);
|
||||
setIsDaojiandanSigned(true); // 签名成功后标记为已签名
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ interface TopBarProps {
|
||||
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'>
|
||||
<div className='flex-1 flex items-center gap-3'>
|
||||
{enableSearch ? (
|
||||
|
||||
@@ -36,30 +36,3 @@ export interface ExamActionRecord {
|
||||
/** 记录时间戳 */
|
||||
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;
|
||||
};
|
||||
Reference in New Issue
Block a user