From c9197808755d144cd524996df92b21bd4a471bd6 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 17:21:39 +0800 Subject: [PATCH] =?UTF-8?q?task-114(=E4=BB=BB=E5=8A=A1=E4=B8=8E=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=88=86=E6=9E=90=E4=B8=AD=E5=BF=83):=20=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=BA=97=E9=93=BA=E6=95=B0=E6=8D=AE=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E6=9D=83=E9=99=90=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit shop-data-api.ts 增加 fetch/saveShopDataTaskPermissions(GET|PUT /api/admin/ shop-data-crawl-task-permissions),复用 task-permission 解析与保存负载。 TDD: task-114.test.ts 8 用例先 RED 后 GREEN。 --- .../src/pages/tasks/shop-data-api.ts | 13 ++++ admin-frontend-vue/tests/task-114.test.ts | 62 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 admin-frontend-vue/tests/task-114.test.ts diff --git a/admin-frontend-vue/src/pages/tasks/shop-data-api.ts b/admin-frontend-vue/src/pages/tasks/shop-data-api.ts index 78bacd5f..26b9ac09 100644 --- a/admin-frontend-vue/src/pages/tasks/shop-data-api.ts +++ b/admin-frontend-vue/src/pages/tasks/shop-data-api.ts @@ -4,8 +4,10 @@ import { parseShopDataTaskPage, type ShopDataTaskPageResult } from './shop-data- import { toShopDataQuery, type ShopDataFilter } from './shop-data-filter.ts' import { toShopDataZipRequest } from './shop-data-download.ts' import { downloadZipHeaderCounts } from './image-video-download.ts' +import { parseTaskPermissionPayload, toPermissionUserIdsPayload, type TaskPermissionItem } from './task-permission.ts' export const SHOP_DATA_CRAWL_TASKS_ENDPOINT = '/api/admin/shop-data-crawl-tasks' +export const SHOP_DATA_TASK_PERMISSIONS_ENDPOINT = '/api/admin/shop-data-crawl-task-permissions' export async function fetchShopDataTaskList( filter: ShopDataFilter, @@ -32,3 +34,14 @@ export async function requestShopDataZipDownload(resultIds: readonly (number | s const counts = downloadZipHeaderCounts(headers as Record) return { blob: data, fileCount: counts.fileCount, errorCount: counts.errorCount } } + +/** 加载店铺数据任务数据范围授权用户:GET /api/admin/shop-data-crawl-task-permissions。 */ +export async function fetchShopDataTaskPermissionUsers(): Promise { + const { data } = await http.get(SHOP_DATA_TASK_PERMISSIONS_ENDPOINT) + return parseTaskPermissionPayload(data) +} + +/** 保存店铺数据任务数据范围授权:PUT /api/admin/shop-data-crawl-task-permissions { user_ids }。 */ +export async function saveShopDataTaskPermissions(userIds: Iterable): Promise { + await http.put(SHOP_DATA_TASK_PERMISSIONS_ENDPOINT, toPermissionUserIdsPayload(userIds)) +} diff --git a/admin-frontend-vue/tests/task-114.test.ts b/admin-frontend-vue/tests/task-114.test.ts new file mode 100644 index 00000000..b42e4c3d --- /dev/null +++ b/admin-frontend-vue/tests/task-114.test.ts @@ -0,0 +1,62 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { readSource } from './helpers.ts' +import { grantedUserIds, parseTaskPermissionPayload, permissionSelectionChanged, toPermissionUserIdsPayload } from '../src/pages/tasks/task-permission.ts' + +const SHOP_DATA_PERM_RESP = { + success: true, + data: [ + { id: 1, username: '张伟', granted: true }, + { id: 2, username: '李四', granted: false }, + { id: 3, username: '王五', granted: true }, + ], +} + +test('test_task_114_shop_data_permission_normal_primary_path', () => { + // 正常主路径:店铺数据权限负载解析并取已授权 id。 + const items = parseTaskPermissionPayload(SHOP_DATA_PERM_RESP) + assert.deepEqual(grantedUserIds(items), [1, 3]) +}) + +test('test_task_114_shop_data_permission_normal_variant_input', () => { + // 正常变体:仅全选/部分授权变更判定。 + const initial = new Set([1, 3]) + assert.equal(permissionSelectionChanged(initial, new Set([1, 3])), false) + assert.equal(permissionSelectionChanged(initial, new Set([1])), true) +}) + +test('test_task_114_shop_data_permission_repeated_is_idempotent', () => { + // 正常重复:保存负载稳定。 + assert.deepEqual(toPermissionUserIdsPayload(new Set([3, 1])), { user_ids: [3, 1] }) +}) + +test('test_task_114_shop_data_permission_boundary_empty_input', () => { + // 边界空值:无授权时的空选择。 + const initial = new Set() + assert.equal(permissionSelectionChanged(initial, new Set()), false) + assert.deepEqual(toPermissionUserIdsPayload(initial), { user_ids: [] }) +}) + +test('test_task_114_shop_data_permission_boundary_single_item', () => { + // 边界单元素:单用户授权变更。 + assert.equal(permissionSelectionChanged(new Set(), new Set([7])), true) +}) + +test('test_task_114_shop_data_permission_boundary_limit_or_missing_field', () => { + // 边界上限/缺字段:仅新增未授权用户时判定为已变更。 + assert.equal(permissionSelectionChanged(new Set([1]), new Set([1, 4])), true) +}) + +test('test_task_114_shop_data_permission_invalid_input_rejected', () => { + // 异常输入:success=false 抛后端 message。 + assert.throws(() => parseTaskPermissionPayload({ success: false, message: '仅超级管理员可配置' }), /仅超级管理员/) +}) + +test('test_task_114_shop_data_permission_dependency_failure_returns_actionable_message', () => { + // 依赖失败/加载走 adapter:GET|PUT /api/admin/shop-data-crawl-task-permissions。 + const api = readSource('src/pages/tasks/shop-data-api.ts') + assert.match(api, /\/api\/admin\/shop-data-crawl-task-permissions/) + assert.match(api, /fetchShopDataTaskPermissionUsers/) + assert.match(api, /saveShopDataTaskPermissions/) + assert.match(api, /http\.put/) +})