From 4c78c6456943a85ad7ef2df26a5b1559e547474e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Sat, 5 Sep 2026 15:58:23 +0800 Subject: [PATCH] =?UTF-8?q?task-70(ASIN=20=E6=95=B0=E6=8D=AE=E4=B8=AD?= =?UTF-8?q?=E5=BF=83):=20=E5=AE=9E=E7=8E=B0=E5=93=81=E7=89=8C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=88=A0=E9=99=A4=E7=A1=AE=E8=AE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit invalid-asin-model.ts 增 invalidAsinDeleteText 二次确认文案(含 ASIN 值/不可恢复语义); invalid-asin-api.ts 增 deleteInvalidAsin DELETE /api/admin/invalid-asin-data/{id}。 8 用例全过,515 单测 + build 绿。 --- .../src/pages/invalidasin/invalid-asin-api.ts | 6 +++ .../pages/invalidasin/invalid-asin-model.ts | 6 +++ admin-frontend-vue/tests/task-70.test.ts | 52 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 admin-frontend-vue/tests/task-70.test.ts diff --git a/admin-frontend-vue/src/pages/invalidasin/invalid-asin-api.ts b/admin-frontend-vue/src/pages/invalidasin/invalid-asin-api.ts index 1281712d..57547a53 100644 --- a/admin-frontend-vue/src/pages/invalidasin/invalid-asin-api.ts +++ b/admin-frontend-vue/src/pages/invalidasin/invalid-asin-api.ts @@ -44,3 +44,9 @@ export async function updateInvalidAsin(id: number, form: InvalidAsinForm, inclu const { data } = await http.put(`${INVALID_ASIN_ENDPOINT}/${id}`, toInvalidAsinUpdateRequest(form, { includeGroup })) unwrap(data) } + +/** 删除品牌数据库记录:DELETE /api/admin/invalid-asin-data/{id}。 */ +export async function deleteInvalidAsin(id: number): Promise { + const { data } = await http.delete(`${INVALID_ASIN_ENDPOINT}/${id}`) + unwrap(data) +} diff --git a/admin-frontend-vue/src/pages/invalidasin/invalid-asin-model.ts b/admin-frontend-vue/src/pages/invalidasin/invalid-asin-model.ts index 8c757793..2421f247 100644 --- a/admin-frontend-vue/src/pages/invalidasin/invalid-asin-model.ts +++ b/admin-frontend-vue/src/pages/invalidasin/invalid-asin-model.ts @@ -38,6 +38,12 @@ export function recordSourceLabel(source: string | null | undefined): string { return (source || '').trim().toUpperCase() === 'MANUAL' ? '手动新增' : '自动导入' } +/** 删除二次确认文案。 */ +export function invalidAsinDeleteText(item: Pick | null | undefined): string { + const value = item?.dataValue || '该 ASIN' + return `确定删除不符合 ASIN“${value}”吗?删除后不可恢复。` +} + /** 解析单条品牌数据库项;缺 id 视为无效。 */ export function toInvalidAsinItem(raw: unknown): InvalidAsinItem | null { if (!raw || typeof raw !== 'object') return null diff --git a/admin-frontend-vue/tests/task-70.test.ts b/admin-frontend-vue/tests/task-70.test.ts new file mode 100644 index 00000000..a4b1a381 --- /dev/null +++ b/admin-frontend-vue/tests/task-70.test.ts @@ -0,0 +1,52 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { readSource } from './helpers.ts' +import { invalidAsinDeleteText } from '../src/pages/invalidasin/invalid-asin-model.ts' + +test('test_task_070_brand_db_delete_normal_primary_path', () => { + // 正常主路径:确认文案含 ASIN 值。 + assert.match(invalidAsinDeleteText({ id: 1, dataValue: 'B0ABC', brand: '', groupId: null, groupName: '', recordSource: 'AUTO' }), /B0ABC/) +}) + +test('test_task_070_brand_db_delete_normal_variant_input', () => { + // 正常变体:空 dataValue 给出兜底文案不崩溃。 + assert.ok(invalidAsinDeleteText({ id: 2, dataValue: '', brand: '', groupId: null, groupName: '', recordSource: 'AUTO' })) +}) + +test('test_task_070_brand_db_delete_normal_repeated_operation_is_idempotent', () => { + // 正常重复:文案纯函数稳定。 + const item = { id: 3, dataValue: 'A', brand: '', groupId: null, groupName: '', recordSource: 'AUTO' } + assert.equal(invalidAsinDeleteText(item), invalidAsinDeleteText(item)) +}) + +test('test_task_070_brand_db_delete_boundary_empty_input', () => { + // 边界空值:缺省条目提示通用文案,不崩溃。 + assert.ok(invalidAsinDeleteText(undefined as never)) +}) + +test('test_task_070_brand_db_delete_boundary_single_item', () => { + // 边界单元素:单条删除文案长度合理。 + const text = invalidAsinDeleteText({ id: 4, dataValue: 'B0XYZ', brand: '', groupId: null, groupName: '', recordSource: 'AUTO' }) + assert.ok(text.length > 0) +}) + +test('test_task_070_brand_db_delete_boundary_limit_or_missing_field', () => { + // 边界上限:品牌字段不影响删除确认。 + const text = invalidAsinDeleteText({ id: 5, dataValue: 'V', brand: '很长的品牌名称不影响删除', groupId: null, groupName: '', recordSource: 'AUTO' }) + assert.match(text, /V/) +}) + +test('test_task_070_brand_db_delete_invalid_input_rejected', () => { + // 异常输入:确认文案标记不可恢复语义。 + assert.match(invalidAsinDeleteText({ id: 6, dataValue: 'X', brand: '', groupId: null, groupName: '', recordSource: 'AUTO' }), /删除/) +}) + +test('test_task_070_brand_db_delete_dependency_failure_returns_actionable_message', () => { + // 依赖失败/删除走 adapter:DELETE /invalid-asin-data/{id}。 + const api = readSource('src/pages/invalidasin/invalid-asin-api.ts') + assert.match(api, /deleteInvalidAsin/) + assert.match(api, /http\.delete/) + assert.match(api, /invalid-asin-data/) + const mod = readSource('src/pages/invalidasin/invalid-asin-model.ts') + assert.equal(/axios|http\./.test(mod), false, '品牌数据库模型保持纯逻辑') +})