From bd940f2e101ae38b6c49360afc1d3141cdbf88fb Mon Sep 17 00:00:00 2001 From: zichun Date: Mon, 1 Jun 2026 16:20:13 +0800 Subject: [PATCH] feat(fe-login): usrApi 登录与版本下拉取数封装 REQ-USR-004 --- frontend/src/api/types.ts | 29 +++++++++++++++++++++++++++++ frontend/src/api/usrApi.ts | 16 ++++++++++++++++ frontend/tests/unit/usrApi.test.ts | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 frontend/src/api/types.ts create mode 100644 frontend/src/api/usrApi.ts create mode 100644 frontend/tests/unit/usrApi.test.ts diff --git a/frontend/src/api/types.ts b/frontend/src/api/types.ts new file mode 100644 index 0000000..0919dd7 --- /dev/null +++ b/frontend/src/api/types.ts @@ -0,0 +1,29 @@ +// REQ-USR-004: 前端跨 task 共享类型契约(对齐 docs/05 § REQ-USR-004 / spec § 4) + +/** 登录用户(对齐 Result<{ token, user }> 的 user 字段) */ +export interface AuthUser { + id: number; + sUserName: string; + sUserType: string; + sLanguage: string; +} + +/** POST /api/usr/login 请求体 */ +export interface LoginPayload { + sUserName: string; + password: string; + companyId: number; +} + +/** POST /api/usr/login 成功响应(已拆 Result.data) */ +export interface LoginResult { + token: string; + user: AuthUser; +} + +/** GET /api/usr/companies 列表项(登录「版本」下拉,D8;sVersion 可空) */ +export interface CompanyOption { + id: number; + sCompanyName: string; + sVersion: string | null; +} diff --git a/frontend/src/api/usrApi.ts b/frontend/src/api/usrApi.ts new file mode 100644 index 0000000..187092c --- /dev/null +++ b/frontend/src/api/usrApi.ts @@ -0,0 +1,16 @@ +// REQ-USR-004: USR 模块 API 封装(登录 + 版本下拉取数)。页面只调本文件,不散用 axios。 +import request from './request'; +import type { LoginPayload, LoginResult, CompanyOption } from './types'; + +// 响应拦截器已拆 Result.data,故此处返回类型即业务数据本体。 +// axios 实例的方法类型仍标注为 AxiosResponse,运行时已被拦截器解包,用 as unknown 桥接。 + +/** POST /api/usr/login —— 登录认证,成功返回 { token, user } */ +export function login(payload: LoginPayload): Promise { + return request.post('/usr/login', payload) as unknown as Promise; +} + +/** GET /api/usr/companies —— 登录「版本」下拉项(公司表只读) */ +export function fetchCompanies(): Promise { + return request.get('/usr/companies') as unknown as Promise; +} diff --git a/frontend/tests/unit/usrApi.test.ts b/frontend/tests/unit/usrApi.test.ts new file mode 100644 index 0000000..ade1d8c --- /dev/null +++ b/frontend/tests/unit/usrApi.test.ts @@ -0,0 +1,48 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +// 桩掉底层 axios 实例(request.ts 的 default 导出) +vi.mock('../../src/api/request', () => { + return { + default: { + post: vi.fn(), + get: vi.fn(), + }, + }; +}); + +import request from '../../src/api/request'; +import { login, fetchCompanies } from '../../src/api/usrApi'; + +const mockedRequest = request as unknown as { + post: ReturnType; + get: ReturnType; +}; + +describe('usrApi', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('login posts to /usr/login with sUserName/password/companyId', async () => { + const result = { + token: 'tk', + user: { id: 1, sUserName: 'admin', sUserType: '超级管理员', sLanguage: '中文' }, + }; + mockedRequest.post.mockResolvedValue(result); + const payload = { sUserName: 'admin', password: 'p', companyId: 9 }; + const ret = await login(payload); + expect(mockedRequest.post).toHaveBeenCalledWith('/usr/login', payload); + expect(ret).toEqual(result); + }); + + it('fetchCompanies gets /usr/companies and returns list', async () => { + const list = [ + { id: 1, sCompanyName: '甲公司', sVersion: '标准版' }, + { id: 2, sCompanyName: '乙公司', sVersion: null }, + ]; + mockedRequest.get.mockResolvedValue(list); + const ret = await fetchCompanies(); + expect(mockedRequest.get).toHaveBeenCalledWith('/usr/companies'); + expect(ret).toEqual(list); + }); +}); -- libgit2 0.22.2