Why: A rejected result-reference request could discard the user text or uploads after the composer cleared. Evidence: 286 frontend tests, TypeScript and the unchanged unused-export gate pass; mixed-input browser regression preserves the draft. Impact: Validate incompatible inputs before clearing, retain failed pending input with its request identity, and require explicit retry while other messages can continue. Refs: feature/workbench-flow-completion review frontend-races finding
50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
// 输入排队(纯数据):回合进行中先入本地队列,终态再逐条发送。
|
|
export interface WorkReference { cardId: string; resultVersion: number; title: string }
|
|
|
|
export interface QueuedMessage {
|
|
id: string
|
|
text: string
|
|
attachmentIds: string[]
|
|
attachmentNames: string[]
|
|
taskRef?: WorkReference
|
|
deliveryError?: string
|
|
}
|
|
|
|
export function newQueuedMessage(text: string, attachmentIds: string[], attachmentNames: string[], taskRef?: WorkReference): QueuedMessage {
|
|
return {
|
|
id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
text,
|
|
attachmentIds,
|
|
attachmentNames,
|
|
...(taskRef ? { taskRef } : {}),
|
|
}
|
|
}
|
|
|
|
export function enqueueMessage(queue: QueuedMessage[], item: QueuedMessage): QueuedMessage[] {
|
|
return [...queue, item]
|
|
}
|
|
|
|
export function enqueueMessageFront(queue: QueuedMessage[], item: QueuedMessage): QueuedMessage[] {
|
|
return [item, ...queue.filter(q => q.id !== item.id)]
|
|
}
|
|
|
|
export function removeQueuedMessage(queue: QueuedMessage[], id: string): QueuedMessage[] {
|
|
return queue.filter(q => q.id !== id)
|
|
}
|
|
|
|
export function replaceQueuedText(queue: QueuedMessage[], id: string, text: string): QueuedMessage[] {
|
|
return queue.map(q => q.id === id ? { ...q, text } : q)
|
|
}
|
|
|
|
// deliveryRequestId 是这条排队消息重发时必须复用的 requestId。
|
|
// 服务端按它去重,避免忙时 409 再入队后写出第二条用户消息。
|
|
export function deliveryRequestId(item: QueuedMessage): string {
|
|
return item.id
|
|
}
|
|
|
|
export function promoteQueuedMessage(queue: QueuedMessage[], id: string): QueuedMessage[] {
|
|
const item = queue.find(q => q.id === id)
|
|
if (!item) return queue
|
|
return enqueueMessageFront(queue, item)
|
|
}
|