@@ -100,6 +100,17 @@ async function getBatch(id: string, image = false) {
100100 return { response, batch : ( await response . json ( ) ) . batch } ;
101101}
102102const start = ( id : string , body : Record < string , unknown > ) => START ( json ( body ) , params ( id ) ) ;
103+ /** 按草稿中的题目顺序取出入库的错题(并发保存时 createdAt 可能相同,不能据此排序) */
104+ async function savedItemsInDraftOrder ( batchId : string ) {
105+ const batch = await database . importBatch . findUniqueOrThrow ( { where : { id : batchId } , select : { draft : true } } ) ;
106+ const keys = ( JSON . parse ( batch . draft ?? '{"items":[]}' ) as { items : { key : string } [ ] } ) . items . map ( ( item ) => item . key ) ;
107+ const tasks = await database . importTask . findMany ( { where : { batchId } , select : { batchItemKey : true , errorItemId : true } } ) ;
108+ const ids = keys
109+ . map ( ( key ) => tasks . find ( ( task ) => task . batchItemKey === key ) ?. errorItemId )
110+ . filter ( ( id ) : id is string => ! ! id ) ;
111+ const items = await database . errorItem . findMany ( { where : { id : { in : ids } } } ) ;
112+ return ids . map ( ( id ) => items . find ( ( item ) => item . id === id ) ! ) ;
113+ }
103114const waitSplit = async ( id : string ) => {
104115 await waitForImportTaskForTest ( id ) ;
105116} ;
@@ -201,7 +212,7 @@ describe('文字多题批次', () => {
201212 expect ( await database . importTask . count ( { where : { batchId : batch . id } } ) ) . toBe ( 8 ) ;
202213 expect ( mocks . reanswerQuestion ) . toHaveBeenCalledTimes ( 8 ) ;
203214 expect ( await database . aiUsage . count ( { where : { kind : 'reanswer' } } ) ) . toBe ( 8 ) ;
204- const items = await database . errorItem . findMany ( { orderBy : { createdAt : 'asc' } } ) ;
215+ const items = await savedItemsInDraftOrder ( batch . id ) ;
205216 expect ( items ) . toHaveLength ( 8 ) ;
206217 expect ( items . every ( ( item ) => item . subjectId === 'math' && item . userId === 'user-1' ) ) . toBe ( true ) ;
207218 expect ( items . map ( ( item ) => item . questionText ) ) . toContain ( draft . items [ 0 ] . text ) ;
@@ -737,7 +748,7 @@ describe('AI 只补标签(analysis=tags)', () => {
737748 expect ( mocks . analyzeImage ) . not . toHaveBeenCalled ( ) ;
738749 expect ( await database . aiUsage . count ( { where : { kind : 'retag' } } ) ) . toBe ( 2 ) ;
739750
740- const items = await database . errorItem . findMany ( { orderBy : { createdAt : 'asc' } } ) ;
751+ const items = await savedItemsInDraftOrder ( batch . id ) ;
741752 expect ( items ) . toHaveLength ( 2 ) ;
742753 // 草稿答案解析保留
743754 expect ( items [ 0 ] . answerText ) . toBe ( '2' ) ;
@@ -814,7 +825,7 @@ describe('AI 只补标签(analysis=tags)', () => {
814825 expect ( mocks . suggestKnowledgeTags ) . toHaveBeenCalledTimes ( 2 ) ;
815826 const { batch : current } = await getBatch ( batch . id ) ;
816827 expect ( current ) . toMatchObject ( { phase : 'done' , counts : { saved : 2 , failed : 0 } } ) ;
817- const items = await database . errorItem . findMany ( { orderBy : { createdAt : 'asc' } } ) ;
828+ const items = await savedItemsInDraftOrder ( batch . id ) ;
818829 expect ( items ) . toHaveLength ( 2 ) ;
819830 expect ( items [ 0 ] . answerText ) . toBe ( '2' ) ;
820831 expect ( items [ 1 ] . answerText ) . toBe ( '4' ) ;
@@ -902,7 +913,7 @@ describe('按原样入库(analysis=none)', () => {
902913 expect ( mocks . analyzeImage ) . not . toHaveBeenCalled ( ) ;
903914 expect ( await database . aiUsage . count ( ) ) . toBe ( 0 ) ;
904915
905- const items = await database . errorItem . findMany ( { orderBy : { createdAt : 'asc' } } ) ;
916+ const items = await savedItemsInDraftOrder ( batch . id ) ;
906917 expect ( items ) . toHaveLength ( 2 ) ;
907918 expect ( items . every ( ( item ) => item . subjectId === 'math' && item . userId === 'user-1' ) ) . toBe ( true ) ;
908919 expect ( items [ 0 ] . questionText ) . toContain ( '计算 1 + 1' ) ;
@@ -919,7 +930,7 @@ describe('按原样入库(analysis=none)', () => {
919930 await start ( batch . id , { version : batch . version , analysis : 'none' } ) ;
920931 await waitForImportBatchTasksForTest ( batch . id ) ;
921932
922- const items = await database . errorItem . findMany ( { orderBy : { createdAt : 'asc' } } ) ;
933+ const items = await savedItemsInDraftOrder ( batch . id ) ;
923934 expect ( items ) . toHaveLength ( 2 ) ;
924935 expect ( items [ 0 ] . questionText ) . toContain ( '某商店上午卖出 30 件' ) ;
925936 expect ( items [ 0 ] . questionText ) . toContain ( '全天卖出多少件' ) ;
@@ -1030,7 +1041,7 @@ describe('按原样入库(analysis=none)', () => {
10301041 await start ( batch . id , { version : batch . version , analysis : 'none' } ) ;
10311042 await waitForImportBatchTasksForTest ( batch . id ) ;
10321043
1033- const items = await database . errorItem . findMany ( { orderBy : { createdAt : 'asc' } } ) ;
1044+ const items = await savedItemsInDraftOrder ( batch . id ) ;
10341045 expect ( items ) . toHaveLength ( 2 ) ;
10351046 // 第一题无答案:占位空格还原为空串
10361047 expect ( items [ 0 ] . answerText ) . toBe ( '' ) ;
@@ -1056,7 +1067,7 @@ describe('按原样入库(analysis=none)', () => {
10561067 expect ( started . status ) . toBe ( 202 ) ;
10571068 await waitForImportBatchTasksForTest ( batch . id ) ;
10581069
1059- const items = await database . errorItem . findMany ( { orderBy : { createdAt : 'asc' } } ) ;
1070+ const items = await savedItemsInDraftOrder ( batch . id ) ;
10601071 expect ( items ) . toHaveLength ( 2 ) ;
10611072 expect ( items [ 0 ] . originalImageUrl ) . toBe ( imageData ) ;
10621073 expect ( items [ 1 ] . originalImageUrl ) . toBe ( '' ) ;
0 commit comments