Files
yuanhe-checkin-electron/src/pages/U1/u1.tsx
2025-12-22 16:57:00 +08:00

206 lines
6.7 KiB
TypeScript

import React, { useState, useEffect, useRef } from "react";
import "./u1.css";
import { useNavigate } from "react-router-dom";
// import { invoke } from "@tauri-apps/api/core";
// import { listen } from "@tauri-apps/api/event";
import idcard from "../../assets/idcard.png";
import semicircle from "../../assets/semicircle.png";
import LongButton from "../../components/LongButton";
import LongButtonLoading from "../../components/LongButtonLoading";
import DecorLine from "../../components/DecorLine";
import { getPatientInfo } from "../../api/hisApi";
const U1: React.FC = () => {
const navigate = useNavigate();
const [reading, setReading] = useState(false);
const [countdown, setCountdown] = useState(6);
const [errorMsg, setErrorMsg] = useState("");
const timerRef = useRef<number | null>(null);
const intervalRef = useRef<number | null>(null);
const errorTimerRef = useRef<number | null>(null);
const isProcessingRef = useRef(false);
// 实时监听身份证读取
useEffect(() => {
// localStorage.setItem("lastIdCardNo", '362331199210243023');
// navigate("/UI6");
// return;
window.electronAPI.startIdCardListen().catch((e: any) => {
console.error("start_idcard_listen failed", e);
window.electronAPI.log("error", `start_idcard_listen failed: ${e}`);
});
window.electronAPI.onIdCardData((e: any) => {
// 如果正在处理中,忽略新的数据
if (isProcessingRef.current) return;
isProcessingRef.current = true;
setReading(true); // 更新 UI 为读取中状态
const payload = e.payload;
try {
if (payload?.id_card_no) {
localStorage.setItem("lastIdCardNo", payload.id_card_no);
// 存储完整的身份证信息供后续页面使用
localStorage.setItem("idCardData", JSON.stringify(payload));
}
} catch (err) {
console.warn("localStorage.setItem failed", err);
}
console.log("[idcard-data]", payload);
window.electronAPI.log("info", `[idcard-data] received`);
window.electronAPI.log(
"info",
`Read IDCard success: ${payload.name} ${payload.id_card_no}`
);
// 清理倒计时
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = null;
}
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
// 重置监听的辅助函数
const resetListening = () => {
window.electronAPI
.stopIdCardListen()
.then(() => {
setTimeout(() => {
window.electronAPI
.startIdCardListen()
.catch((e: any) => console.error(e));
}, 1000);
})
.catch(() => { });
};
// 先验证档案信息,查询到才跳转
const idCardNo = payload.id_card_no;
if (!idCardNo) {
setErrorMsg("未读取到身份证号");
setReading(false);
isProcessingRef.current = false;
resetListening();
return;
}
getPatientInfo(idCardNo)
.then((res) => {
if (res.Status === 200 && res.Data) {
// 查询成功,跳转到 u2
window.electronAPI.stopIdCardListen().catch(() => { });
setReading(false);
isProcessingRef.current = false;
navigate("/u2");
} else {
// 未查询到档案信息,显示错误提示,不跳转
setErrorMsg("未查询到您的档案信息,详情请咨询前台工作人员!");
setReading(false);
isProcessingRef.current = false;
resetListening();
}
})
.catch((err) => {
console.error("getPatientInfo error", err);
setErrorMsg("获取用户信息异常,请联系前台工作人员");
setReading(false);
isProcessingRef.current = false;
resetListening();
});
});
window.electronAPI.onIdCardError((e: any) => {
console.error("[idcard-error]", e.payload);
window.electronAPI.log("error", `[idcard-error] ${e.payload}`);
});
return () => {
window.electronAPI.stopIdCardListen().catch(() => { });
window.electronAPI.removeIdCardListeners();
if (timerRef.current) clearTimeout(timerRef.current);
if (intervalRef.current) clearInterval(intervalRef.current);
if (errorTimerRef.current) clearTimeout(errorTimerRef.current);
};
}, [navigate]);
// 错误信息 10 秒后自动消失
useEffect(() => {
if (errorMsg) {
if (errorTimerRef.current) clearTimeout(errorTimerRef.current);
errorTimerRef.current = window.setTimeout(() => {
setErrorMsg("");
errorTimerRef.current = null;
}, 10000);
}
return () => {
if (errorTimerRef.current) {
clearTimeout(errorTimerRef.current);
errorTimerRef.current = null;
}
};
}, [errorMsg]);
const handleStart = () => {
if (reading) return; // 避免重复点击
setReading(true);
// isProcessingRef.current = true; // 不需要手动设置,等待读卡数据
setCountdown(6);
setErrorMsg(""); // 清空之前的错误信息
// 6 秒倒计时逻辑
if (intervalRef.current) clearInterval(intervalRef.current);
intervalRef.current = window.setInterval(() => {
setCountdown((prev) => {
if (prev <= 1) {
if (intervalRef.current) clearInterval(intervalRef.current);
return 0;
}
return prev - 1;
});
}, 1000);
// 6 秒超时恢复
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = null;
}
timerRef.current = window.setTimeout(() => {
console.warn("未在 6 秒内读取到身份证信息,恢复初始状态");
setReading(false);
// isProcessingRef.current = false;
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
timerRef.current = null;
}, 6000);
};
return (
<div className="u1-root">
<span className="u1-title">
使
<br />
</span>
<DecorLine />
<img alt="card reader" src={idcard} />
<div className="u1-instruction-wrapper">
<span className="u1-instruction"></span>
{errorMsg && <span className="u1-error">{errorMsg}</span>}
</div>
<img className="u1-semicircle" alt="start button" src={semicircle} />
{!reading && <LongButton text="开始签到" onClick={handleStart} />}
{reading && (
<LongButtonLoading text={`身份信息读取中... ${countdown}s`} />
)}
</div>
);
};
export default U1;