feat(label-studio): 添加编辑器就绪状态检查和任务ID验证

- 添加 expectedTaskIdRef 用于跟踪预期任务ID
- 添加 lsReady 状态管理编辑器就绪状态
- 在任务加载时重置编辑器就绪状态和预期任务ID
- 实现 LS_READY 消息处理和任务ID验证逻辑
- 添加错误处理时设置编辑器为未就绪状态
- 更新加载提示显示不同状态信息
- 改进条件渲染确保编辑器完全准备就绪后显示
This commit is contained in:
2026-01-12 22:44:13 +08:00
parent e1c41a93c3
commit 70b2ddd4a2

View File

@@ -42,6 +42,7 @@ export default function LabelStudioTextEditor() {
const origin = useMemo(() => window.location.origin, []); const origin = useMemo(() => window.location.origin, []);
const iframeRef = useRef<HTMLIFrameElement | null>(null); const iframeRef = useRef<HTMLIFrameElement | null>(null);
const initSeqRef = useRef(0); const initSeqRef = useRef(0);
const expectedTaskIdRef = useRef<number | null>(null);
const [loadingProject, setLoadingProject] = useState(true); const [loadingProject, setLoadingProject] = useState(true);
const [loadingTasks, setLoadingTasks] = useState(false); const [loadingTasks, setLoadingTasks] = useState(false);
@@ -49,6 +50,7 @@ export default function LabelStudioTextEditor() {
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const [iframeReady, setIframeReady] = useState(false); const [iframeReady, setIframeReady] = useState(false);
const [lsReady, setLsReady] = useState(false);
const [project, setProject] = useState<EditorProjectInfo | null>(null); const [project, setProject] = useState<EditorProjectInfo | null>(null);
const [tasks, setTasks] = useState<EditorTaskListItem[]>([]); const [tasks, setTasks] = useState<EditorTaskListItem[]>([]);
const [selectedFileId, setSelectedFileId] = useState<string>(""); const [selectedFileId, setSelectedFileId] = useState<string>("");
@@ -109,6 +111,8 @@ export default function LabelStudioTextEditor() {
const seq = ++initSeqRef.current; const seq = ++initSeqRef.current;
setLoadingTaskDetail(true); setLoadingTaskDetail(true);
setLsReady(false);
expectedTaskIdRef.current = null;
try { try {
const resp = (await getEditorTaskUsingGet(projectId, fileId)) as any; const resp = (await getEditorTaskUsingGet(projectId, fileId)) as any;
@@ -119,6 +123,7 @@ export default function LabelStudioTextEditor() {
} }
if (seq !== initSeqRef.current) return; if (seq !== initSeqRef.current) return;
expectedTaskIdRef.current = Number(task?.id) || null;
postToIframe("LS_INIT", { postToIframe("LS_INIT", {
labelConfig: project.labelConfig, labelConfig: project.labelConfig,
task, task,
@@ -179,6 +184,8 @@ export default function LabelStudioTextEditor() {
setTasks([]); setTasks([]);
setSelectedFileId(""); setSelectedFileId("");
initSeqRef.current = 0; initSeqRef.current = 0;
setLsReady(false);
expectedTaskIdRef.current = null;
if (projectId) loadProject(); if (projectId) loadProject();
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -207,6 +214,15 @@ export default function LabelStudioTextEditor() {
return; return;
} }
if (msg.type === "LS_READY") {
const readyTaskId = msg.payload?.taskId;
if (expectedTaskIdRef.current && readyTaskId) {
if (Number(readyTaskId) !== expectedTaskIdRef.current) return;
}
setLsReady(true);
return;
}
if (msg.type === "LS_EXPORT_RESULT") { if (msg.type === "LS_EXPORT_RESULT") {
saveFromExport(msg.payload); saveFromExport(msg.payload);
return; return;
@@ -220,6 +236,7 @@ export default function LabelStudioTextEditor() {
if (msg.type === "LS_ERROR") { if (msg.type === "LS_ERROR") {
message.error(msg.payload?.message || "编辑器发生错误"); message.error(msg.payload?.message || "编辑器发生错误");
setLsReady(false);
} }
}; };
@@ -332,9 +349,17 @@ export default function LabelStudioTextEditor() {
<Card title="编辑器" className="flex-1 h-full flex flex-col" bodyStyle={{ padding: 0, flex: 1, overflow: "hidden" }}> <Card title="编辑器" className="flex-1 h-full flex flex-col" bodyStyle={{ padding: 0, flex: 1, overflow: "hidden" }}>
<div className="relative h-full"> <div className="relative h-full">
{loadingTaskDetail && ( {(!iframeReady || loadingTaskDetail || (selectedFileId && !lsReady)) && (
<div className="absolute inset-0 z-10 flex items-center justify-center bg-white/70"> <div className="absolute inset-0 z-10 flex items-center justify-center bg-white/70">
<Spin /> <Spin
tip={
!iframeReady
? "编辑器资源加载中..."
: loadingTaskDetail
? "任务数据加载中..."
: "编辑器初始化中..."
}
/>
</div> </div>
)} )}
<iframe <iframe