fix: isolate attachment submission state

This commit is contained in:
2026-08-24 01:50:04 +08:00
parent bec93d0918
commit 1ca0249e69
8 changed files with 320 additions and 21 deletions

View File

@@ -301,7 +301,8 @@ export function CodingChatPanel({
]);
const handleAddFiles = useCallback((files: File[]) => {
if (!draftKey) return;
if (!draftKey
|| (targetConversationId && submissionFlightsRef.current.has(targetConversationId))) return;
const accepted: LocalComposerAttachment[] = [];
const remaining = Math.max(0, CODING_ATTACHMENT_MAX_COUNT - localAttachments.length);
let validationError = files.length > remaining
@@ -335,10 +336,11 @@ export function CodingChatPanel({
...current,
[draftKey]: [...(current[draftKey] ?? []), ...accepted],
}));
}, [draftKey, localAttachments.length]);
}, [draftKey, localAttachments.length, targetConversationId]);
const handleRemoveAttachment = useCallback((id: string) => {
if (!draftKey) return;
if (!draftKey
|| (targetConversationId && submissionFlightsRef.current.has(targetConversationId))) return;
setAttachmentsByDraftKey((current) => {
const attachment = current[draftKey]?.find((item) => item.id === id);
if (attachment) URL.revokeObjectURL(attachment.previewUrl);
@@ -349,7 +351,12 @@ export function CodingChatPanel({
});
uploadedAttachmentsRef.current.delete(id);
uploadFlightsRef.current.delete(id);
}, [draftKey]);
setSubmissionErrors((current) => {
const next = { ...current };
delete next[draftKey];
return next;
});
}, [draftKey, targetConversationId]);
const prepareAttachments = useCallback(async (
attachments: LocalComposerAttachment[],

View File

@@ -91,6 +91,7 @@ export function CodingComposer({
type="file"
accept="image/png,image/jpeg,image/webp,image/gif"
multiple
disabled={!editable || submitting}
className="sr-only"
data-testid="coding-file-attachment-input"
onChange={(event) => {
@@ -110,8 +111,9 @@ export function CodingComposer({
/>
<button
type="button"
className="absolute right-1 top-1 flex h-10 w-10 translate-x-2 -translate-y-2 items-end justify-start rounded-full bg-foreground/85 p-1.5 text-background transition-[background-color,scale] duration-150 ease-out hover:bg-foreground active:scale-[0.96]"
className="absolute right-1 top-1 flex h-10 w-10 translate-x-2 -translate-y-2 items-end justify-start rounded-full bg-foreground/85 p-1.5 text-background transition-[background-color,scale] duration-150 ease-out hover:bg-foreground active:scale-[0.96] disabled:cursor-not-allowed disabled:opacity-60"
aria-label={`移除图片 ${attachment.name}`}
disabled={submitting}
onClick={() => onRemoveAttachment(attachment.id)}
>
<X className="h-3.5 w-3.5" aria-hidden="true" />
@@ -133,6 +135,7 @@ export function CodingComposer({
if (canSend) onSubmit();
}}
onPaste={(event) => {
if (submitting) return;
const files = Array.from(event.clipboardData.files).filter((file) => file.type.startsWith('image/'));
if (files.length > 0) onAddFiles(files);
}}