From 359f3ce1c9da3a2480b03f7139fe735be5cc111e 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 22:26:52 +0800 Subject: [PATCH] =?UTF-8?q?task-270(admin.html=E8=A7=82=E6=84=9F=E5=AF=B9?= =?UTF-8?q?=E9=BD=90):=20=E4=BF=AE=E6=AD=A3=E5=8E=BB=E9=87=8D=E5=88=86?= =?UTF-8?q?=E7=BB=84=E9=80=89=E9=A1=B9=E6=8E=A5=E5=8F=A3=E4=B8=BA=20/shop-?= =?UTF-8?q?manages/groups=20+=20live=20=E7=9C=9F=E5=AE=9E=20smoke=20?= =?UTF-8?q?=E9=80=9A=E8=BF=87(=E7=99=BB=E5=BD=95/=E8=8F=9C=E5=8D=95/?= =?UTF-8?q?=E5=90=84=E5=9F=9F=E5=88=97=E8=A1=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/asin/dedupe-total-api.ts | 2 +- .../tests/live/task-270-align-live.test.ts | 80 +++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 admin-frontend-vue/tests/live/task-270-align-live.test.ts diff --git a/admin-frontend-vue/src/pages/asin/dedupe-total-api.ts b/admin-frontend-vue/src/pages/asin/dedupe-total-api.ts index badb7b4a..ee6468cb 100644 --- a/admin-frontend-vue/src/pages/asin/dedupe-total-api.ts +++ b/admin-frontend-vue/src/pages/asin/dedupe-total-api.ts @@ -6,7 +6,7 @@ import { parseDedupeTotalPage, type DedupeTotalPageResult } from './dedupe-total export const DEDUPE_TOTAL_ENDPOINT = '/api/admin/dedupe-total-data' /** 数据权限分组选项源(与店铺/去重共用同一分组集)。 */ -export const DEDUPE_GROUPS_ENDPOINT = '/api/admin/shop-manage-groups' +export const DEDUPE_GROUPS_ENDPOINT = '/api/admin/shop-manages/groups' export async function fetchDedupeTotalList(params: Partial = {}): Promise { const normalized = normalizeAsinPageParams(params) diff --git a/admin-frontend-vue/tests/live/task-270-align-live.test.ts b/admin-frontend-vue/tests/live/task-270-align-live.test.ts new file mode 100644 index 00000000..5048aabd --- /dev/null +++ b/admin-frontend-vue/tests/live/task-270-align-live.test.ts @@ -0,0 +1,80 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { parseCurrentUser, parseMenuTree } from '../../src/api/session-model.ts' + +// module 13 task 270:本地 Java(默认 18080) 真实 smoke——登录、会话、菜单树与代表性后台列表可达。 +// 门控:AIIMAGE_LIVE_USER/AIIMAGE_LIVE_PASS 缺省跳过(与既有 live 约定一致)。 + +const BASE = process.env.AIIMAGE_LIVE_BASE || 'http://127.0.0.1:18080' +const USER = process.env.AIIMAGE_LIVE_USER || '' +const PASS = process.env.AIIMAGE_LIVE_PASS || '' +const DEVICE = 'claude-module13-align-smoke' +const HAS_CREDS = Boolean(USER && PASS) + +async function loginToken(): Promise { + const res = await fetch(`${BASE}/login`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username: USER, password: PASS, deviceId: DEVICE }), + }) + const body = (await res.json()) as { success?: boolean; message?: string; data?: { token?: string } } + if (!body.success || !body.data?.token) throw new Error(body.message || 'login failed') + return body.data.token +} + +async function getJson(token: string, path: string): Promise<{ status: number; body: unknown }> { + const res = await fetch(`${BASE}${path}`, { headers: { Authorization: `Bearer ${token}` } }) + const body = (await res.json().catch(() => null)) as unknown + return { status: res.status, body } +} + +test('test_live_270_login_and_current_user', { skip: !HAS_CREDS }, async () => { + const token = await loginToken() + assert.ok(token.length > 0, '登录应返回 token') + const { status, body } = await getJson(token, '/api/admin/current-user') + assert.equal(status, 200) + const user = parseCurrentUser(body) + assert.ok(user.username.length > 0) + assert.ok(['super_admin', 'admin', 'normal'].includes(user.role)) +}) + +test('test_live_270_admin_menu_tree', { skip: !HAS_CREDS }, async () => { + const token = await loginToken() + const { status, body } = await getJson(token, '/api/admin/current-user/menus') + assert.equal(status, 200) + const tree = parseMenuTree(body) + assert.ok(tree.length > 0, '超级管理员应能取到后台菜单树') + assert.ok(tree.some((n) => n.children?.length), '菜单树含分组') +}) + +test('test_live_270_users_list_reachable', { skip: !HAS_CREDS }, async () => { + const token = await loginToken() + const { status, body } = await getJson(token, '/api/admin/users?page=1&page_size=10') + assert.equal(status, 200) + const env = body as { success?: boolean } + assert.equal(env.success, true, '用户列表接口 success=true') +}) + +test('test_live_270_shop_manage_groups_reachable', { skip: !HAS_CREDS }, async () => { + const token = await loginToken() + const { status, body } = await getJson(token, '/api/admin/shop-manages/groups') + assert.equal(status, 200) + const env = body as { success?: boolean } + assert.equal(env.success, true, '店铺分组接口 success=true') +}) + +test('test_live_270_invalid_asin_list_reachable', { skip: !HAS_CREDS }, async () => { + const token = await loginToken() + const { status, body } = await getJson(token, '/api/admin/invalid-asin-data?page=1&page_size=5') + assert.equal(status, 200) + const env = body as { success?: boolean } + assert.equal(env.success, true, '品牌数据库(不符合ASIN)列表 success=true') +}) + +test('test_live_270_product_categories_reachable', { skip: !HAS_CREDS }, async () => { + const token = await loginToken() + const { status, body } = await getJson(token, '/api/admin/product-categories') + assert.equal(status, 200) + const env = body as { success?: boolean } + assert.equal(env.success, true, '商品类目接口 success=true') +})