From 1c4eeb3e33df051eb6e39298d3146d65f8b8f52e Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Sat, 29 Aug 2026 17:10:39 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(voice):=20=E4=BF=AE=E5=A4=8D=E5=85=8B?= =?UTF-8?q?=E9=9A=86=E9=9F=B3=E8=89=B2=E5=BC=B9=E7=AA=97=E9=80=89=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=97=A0=E5=8F=8D=E5=BA=94=E6=AD=BB=E9=94=81=E2=80=94?= =?UTF-8?q?=E2=80=94=E7=A7=BB=E9=99=A4=E4=B8=89=E5=A4=84=E8=AF=AF=E7=94=A8?= =?UTF-8?q?=E7=9A=84=E6=8F=90=E4=BA=A4=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit isSubmittingRef 是 handleSubmit 的防重入锁,被错误写进 resetState、 handleFileChange else、handleDrop else: - resetState 在弹窗打开时执行,上锁后永不复位 → 弹窗一开即死锁 - 选文件/拖拽文件校验通过后先检查锁并 return → 文件被静默拦截 且这三处上锁后都没有对应解锁路径。 移除这三对误用语句;handleSubmit 内的上锁/成功·catch 复位逻辑保持原样。 isMountedRef、OSS 直传、useAudioRecorder 均不动。 --- apps/web/src/components/voice/CloneModal/index.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/web/src/components/voice/CloneModal/index.tsx b/apps/web/src/components/voice/CloneModal/index.tsx index 28f2beee9..d86e7d34f 100644 --- a/apps/web/src/components/voice/CloneModal/index.tsx +++ b/apps/web/src/components/voice/CloneModal/index.tsx @@ -57,8 +57,6 @@ const CloneModal: React.FC = ({ open, onClose, onSuccess }) => setVoiceDescription("") setSelectedFile(null) setDragActive(false) - if (isSubmittingRef.current) return - isSubmittingRef.current = true setErrorMessage("") resetRecorder() }, [getNextDefaultName, resetRecorder]) @@ -99,8 +97,6 @@ const CloneModal: React.FC = ({ open, onClose, onSuccess }) => setErrorMessage(error) setSelectedFile(null) } else { - if (isSubmittingRef.current) return - isSubmittingRef.current = true setErrorMessage("") setSelectedFile(file) resetRecorder() @@ -132,8 +128,6 @@ const CloneModal: React.FC = ({ open, onClose, onSuccess }) => setErrorMessage(error) setSelectedFile(null) } else { - if (isSubmittingRef.current) return - isSubmittingRef.current = true setErrorMessage("") setSelectedFile(file) resetRecorder() -- 2.54.0 From 81fac3a6e86945bcfe4d1d5d0b01f7b52faa2987 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Sat, 29 Aug 2026 17:25:54 +0800 Subject: [PATCH 2/2] =?UTF-8?q?docs(voice):=20CloneModal=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E6=8F=90=E4=BA=A4=E9=94=81=E8=BE=B9=E7=95=8C=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=EF=BC=88=E5=9B=9E=E5=BA=94=20AI=20review=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 文件选择/拖拽/弹窗重置均为同步 state 操作无异步竞态,防重入只属于 handleSubmit(isSubmittingRef + isProcessing 双保险); resetState 此前上锁且无复位路径导致弹窗打开即死锁,故不设锁。 --- apps/web/src/components/voice/CloneModal/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/web/src/components/voice/CloneModal/index.tsx b/apps/web/src/components/voice/CloneModal/index.tsx index d86e7d34f..be564f067 100644 --- a/apps/web/src/components/voice/CloneModal/index.tsx +++ b/apps/web/src/components/voice/CloneModal/index.tsx @@ -57,6 +57,8 @@ const CloneModal: React.FC = ({ open, onClose, onSuccess }) => setVoiceDescription("") setSelectedFile(null) setDragActive(false) + // 注意:resetState 不得触碰 isSubmittingRef——提交锁仅属于 handleSubmit; + // 此前在此上锁且无复位路径,弹窗打开即死锁 setErrorMessage("") resetRecorder() }, [getNextDefaultName, resetRecorder]) @@ -97,6 +99,8 @@ const CloneModal: React.FC = ({ open, onClose, onSuccess }) => setErrorMessage(error) setSelectedFile(null) } else { + // 文件选择为纯同步 state 设置,无异步竞态;防重入只属于提交动作, + // 由 handleSubmit 的 isSubmittingRef + isProcessing 保证,此处不设锁 setErrorMessage("") setSelectedFile(file) resetRecorder() @@ -128,6 +132,8 @@ const CloneModal: React.FC = ({ open, onClose, onSuccess }) => setErrorMessage(error) setSelectedFile(null) } else { + // 文件选择为纯同步 state 设置,无异步竞态;防重入只属于提交动作, + // 由 handleSubmit 的 isSubmittingRef + isProcessing 保证,此处不设锁 setErrorMessage("") setSelectedFile(file) resetRecorder() -- 2.54.0