import React, { useCallback, useEffect, useState } from 'react'; import { Button, Image, Radio, RadioGroup, ScrollView, Text, View } from '@tarojs/components'; import Taro, { usePullDownRefresh } from '@tarojs/taro'; import styles from './index.module.scss'; import { listLampSteps, listLampTests, updateLampResult, updateLampStep, uploadLampResultImage, type LampTest, type LampTestStep, } from '@/api/lamp'; import { formatRelativeTime } from '@/utils/format'; const STATUS_LABELS: Record = { pending: '待检测', testing: '检测中', resulted: '已出结果', }; const RESULT_LABELS: Record = { positive: '阳性', negative: '阴性', invalid: '无效', }; const METHOD_LABELS: Record = { lamp: 'LAMP', qpcr: 'qPCR', sers: 'SERS', hyperspectral: '高光谱', }; const LampPage: React.FC = () => { const [tests, setTests] = useState([]); const [stepsMap, setStepsMap] = useState>({}); const [expandedId, setExpandedId] = useState(''); const [result, setResult] = useState(''); const [loading, setLoading] = useState(true); const fetchData = useCallback(async () => { try { const list = await listLampTests().catch(() => [] as LampTest[]); setTests(list); const map: Record = {}; await Promise.all( list.map(async (t) => { map[t.id] = await listLampSteps(t.id).catch(() => [] as LampTestStep[]); }), ); setStepsMap(map); } finally { setLoading(false); } }, []); useEffect(() => { fetchData(); }, [fetchData]); usePullDownRefresh(() => { fetchData().then(() => Taro.stopPullDownRefresh()); }); const toggleExpand = (t: LampTest) => { if (expandedId === t.id) { setExpandedId(''); return; } setExpandedId(t.id); setResult(t.result || ''); }; const handleStepToggle = async (t: LampTest, s: LampTestStep, done: boolean) => { await updateLampStep(t.id, s.stepNo, done); setStepsMap((prev) => ({ ...prev, [t.id]: (prev[t.id] || []).map((x) => (x.stepNo === s.stepNo ? { ...x, done } : x)), })); }; const handleChooseImage = (t: LampTest) => { Taro.chooseImage({ count: 1, sizeType: ['compressed'], success: async (res) => { const path = res.tempFilePaths[0]; try { const up = await uploadLampResultImage(t.id, path); setTests((prev) => prev.map((x) => (x.id === t.id ? { ...x, resultImageUrl: up.url } : x)), ); Taro.showToast({ title: '照片已上传', icon: 'success' }); } catch (err) { Taro.showToast({ title: err instanceof Error ? err.message : '上传失败', icon: 'none', }); } }, }); }; const handleSaveResult = async (t: LampTest) => { if (!result) { Taro.showToast({ title: '请选择检测结果', icon: 'none' }); return; } await updateLampResult(t.id, result); Taro.showToast({ title: '结果已保存', icon: 'success' }); fetchData(); }; return ( {tests.map((t) => { const steps = stepsMap[t.id] || []; const doneCount = steps.filter((s) => s.done).length; const expanded = expandedId === t.id; return ( toggleExpand(t)}> {(t.diseases || []).join('、') || 'LAMP 检测'} {METHOD_LABELS[t.method || 'lamp']} · {STATUS_LABELS[t.status] || t.status} {t.sampleInfo ? ` · ${t.sampleInfo}` : ''} · {formatRelativeTime(t.createdAt)} {expanded ? '▲' : '▼'} {expanded ? ( 操作步骤({doneCount}/{steps.length}) {steps.map((s) => ( handleStepToggle(t, s, !s.done)}> {s.done ? '✅' : '⬜'} {s.stepNo}. {s.name} ))} 结果照片 {t.resultImageUrl ? ( ) : null} 检测结果(天蓝=阳性,紫罗兰=阴性) setResult(e.detail.value[0])}> 阳性 阴性 无效 {t.result ? 当前结果:{RESULT_LABELS[t.result]} : null} {t.crossStatus && t.crossStatus !== 'pending' ? ( {t.crossStatus === 'consistent' ? '交叉验证:一致(确认诊断)✓' : `交叉验证:不一致 ⚠ ${t.crossReason || '建议专家会诊'}`} ) : null} ) : null} ); })} {!loading && tests.length === 0 ? ( 暂无检测任务单 ) : null} ); }; export default LampPage;