From dc6341d24ef9e6270f81e0d7425c699c4065edb9 Mon Sep 17 00:00:00 2001 From: liyongde <1419499670@qq.com> Date: Mon, 17 Aug 2026 21:37:12 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=A0=A1=E9=AA=8C=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E5=93=8D=E5=BA=94=E4=B8=80=E8=87=B4=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/batch-form-model.test.ts | 93 +++++++++++++++++++ .../modules/batch-form-model.ts | 32 +++++-- 2 files changed, 117 insertions(+), 8 deletions(-) diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/lms/subpackagerelation/modules/batch-form-model.test.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/lms/subpackagerelation/modules/batch-form-model.test.ts index aa803c3b..fe62ce6f 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/lms/subpackagerelation/modules/batch-form-model.test.ts +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/lms/subpackagerelation/modules/batch-form-model.test.ts @@ -233,6 +233,99 @@ describe('batch-form-model', () => { ); }); + it('keeps every row when failures repeat the same known row', () => { + const rows = [createBatchRow(), createBatchRow()]; + const failure = { + clientKey: rows[0]!.clientKey, + rowIndex: 1, + errorCode: 'INVALID', + message: '第一行失败', + }; + const result = applyBatchResult(rows, { + successCount: 0, + failureCount: 2, + failures: [failure, failure], + }); + const generalError = '批量保存结果无法匹配,请核对后重试'; + + expect(result.rows).toEqual(rows); + expect(result.rowErrors).toEqual( + new Map(rows.map((row) => [row.clientKey, generalError])), + ); + }); + + it('keeps every row when unknown failure keys resolve to the same row', () => { + const rows = [createBatchRow(), createBatchRow()]; + const result = applyBatchResult(rows, { + successCount: 0, + failureCount: 2, + failures: [ + { + clientKey: 'unknown-a', + rowIndex: 1, + errorCode: 'INVALID_A', + message: '失败 A', + }, + { + clientKey: 'unknown-b', + rowIndex: 1, + errorCode: 'INVALID_B', + message: '失败 B', + }, + ], + }); + const generalError = '批量保存结果无法匹配,请核对后重试'; + + expect(result.rows).toEqual(rows); + expect(result.rowErrors).toEqual( + new Map(rows.map((row) => [row.clientKey, generalError])), + ); + }); + + it('keeps every row when response counts do not cover all input rows', () => { + const rows = [createBatchRow(), createBatchRow()]; + const result = applyBatchResult(rows, { + successCount: 0, + failureCount: 1, + failures: [ + { + clientKey: rows[0]!.clientKey, + rowIndex: 1, + errorCode: 'INVALID', + message: '第一行失败', + }, + ], + }); + const generalError = '批量保存结果无法匹配,请核对后重试'; + + expect(result.rows).toEqual(rows); + expect(result.rowErrors).toEqual( + new Map(rows.map((row) => [row.clientKey, generalError])), + ); + }); + + it('keeps every row when failure count differs from failure details', () => { + const rows = [createBatchRow(), createBatchRow()]; + const result = applyBatchResult(rows, { + successCount: 0, + failureCount: 2, + failures: [ + { + clientKey: rows[0]!.clientKey, + rowIndex: 1, + errorCode: 'INVALID', + message: '第一行失败', + }, + ], + }); + const generalError = '批量保存结果无法匹配,请核对后重试'; + + expect(result.rows).toEqual(rows); + expect(result.rowErrors).toEqual( + new Map(rows.map((row) => [row.clientKey, generalError])), + ); + }); + it('returns no rows or errors when every row succeeds', () => { const result = applyBatchResult([createBatchRow()], { successCount: 1, diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/lms/subpackagerelation/modules/batch-form-model.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/lms/subpackagerelation/modules/batch-form-model.ts index 53f1e8a7..17d807ca 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/lms/subpackagerelation/modules/batch-form-model.ts +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/lms/subpackagerelation/modules/batch-form-model.ts @@ -81,17 +81,29 @@ export function applyBatchResult( result: LmsSubPackageRelationApi.BatchCreateResult, ): { rows: BatchFormRow[]; rowErrors: Map } { const generalError = '批量保存结果无法匹配,请核对后重试'; + const unsafeResult = () => ({ + rows, + rowErrors: new Map(rows.map((item) => [item.clientKey, generalError])), + }); const rowByClientKey = new Map(); for (const row of rows) { if (rowByClientKey.has(row.clientKey)) { - return { - rows, - rowErrors: new Map(rows.map((item) => [item.clientKey, generalError])), - }; + return unsafeResult(); } rowByClientKey.set(row.clientKey, row); } + if ( + !Number.isInteger(result.successCount) || + result.successCount < 0 || + !Number.isInteger(result.failureCount) || + result.failureCount < 0 || + result.successCount + result.failureCount !== rows.length || + result.failureCount !== result.failures.length + ) { + return unsafeResult(); + } + if (result.failures.length === 0) { return { rows: [], rowErrors: new Map() }; } @@ -105,17 +117,21 @@ export function applyBatchResult( (rowByKey && rowByIndex?.clientKey !== rowByKey.clientKey) || (!rowByKey && !rowByIndex) ) { - return { - rows, - rowErrors: new Map(rows.map((item) => [item.clientKey, generalError])), - }; + return unsafeResult(); } const matchedRow = rowByKey ?? rowByIndex!; + if (failedClientKeys.has(matchedRow.clientKey)) { + return unsafeResult(); + } failedClientKeys.add(matchedRow.clientKey); rowErrors.set(matchedRow.clientKey, failure.message); } + if (failedClientKeys.size !== result.failureCount) { + return unsafeResult(); + } + return { rows: rows.filter((row) => failedClientKeys.has(row.clientKey)), rowErrors,