Commit bd940f2e101ae38b6c49360afc1d3141cdbf88fb

Authored by zichun
1 parent 9e022006

feat(fe-login): usrApi 登录与版本下拉取数封装 REQ-USR-004

frontend/src/api/types.ts 0 → 100644
  1 +// REQ-USR-004: 前端跨 task 共享类型契约(对齐 docs/05 § REQ-USR-004 / spec § 4)
  2 +
  3 +/** 登录用户(对齐 Result<{ token, user }> 的 user 字段) */
  4 +export interface AuthUser {
  5 + id: number;
  6 + sUserName: string;
  7 + sUserType: string;
  8 + sLanguage: string;
  9 +}
  10 +
  11 +/** POST /api/usr/login 请求体 */
  12 +export interface LoginPayload {
  13 + sUserName: string;
  14 + password: string;
  15 + companyId: number;
  16 +}
  17 +
  18 +/** POST /api/usr/login 成功响应(已拆 Result.data) */
  19 +export interface LoginResult {
  20 + token: string;
  21 + user: AuthUser;
  22 +}
  23 +
  24 +/** GET /api/usr/companies 列表项(登录「版本」下拉,D8;sVersion 可空) */
  25 +export interface CompanyOption {
  26 + id: number;
  27 + sCompanyName: string;
  28 + sVersion: string | null;
  29 +}
... ...
frontend/src/api/usrApi.ts 0 → 100644
  1 +// REQ-USR-004: USR 模块 API 封装(登录 + 版本下拉取数)。页面只调本文件,不散用 axios。
  2 +import request from './request';
  3 +import type { LoginPayload, LoginResult, CompanyOption } from './types';
  4 +
  5 +// 响应拦截器已拆 Result.data,故此处返回类型即业务数据本体。
  6 +// axios 实例的方法类型仍标注为 AxiosResponse,运行时已被拦截器解包,用 as unknown 桥接。
  7 +
  8 +/** POST /api/usr/login —— 登录认证,成功返回 { token, user } */
  9 +export function login(payload: LoginPayload): Promise<LoginResult> {
  10 + return request.post('/usr/login', payload) as unknown as Promise<LoginResult>;
  11 +}
  12 +
  13 +/** GET /api/usr/companies —— 登录「版本」下拉项(公司表只读) */
  14 +export function fetchCompanies(): Promise<CompanyOption[]> {
  15 + return request.get('/usr/companies') as unknown as Promise<CompanyOption[]>;
  16 +}
... ...
frontend/tests/unit/usrApi.test.ts 0 → 100644
  1 +import { describe, it, expect, vi, beforeEach } from 'vitest';
  2 +
  3 +// 桩掉底层 axios 实例(request.ts 的 default 导出)
  4 +vi.mock('../../src/api/request', () => {
  5 + return {
  6 + default: {
  7 + post: vi.fn(),
  8 + get: vi.fn(),
  9 + },
  10 + };
  11 +});
  12 +
  13 +import request from '../../src/api/request';
  14 +import { login, fetchCompanies } from '../../src/api/usrApi';
  15 +
  16 +const mockedRequest = request as unknown as {
  17 + post: ReturnType<typeof vi.fn>;
  18 + get: ReturnType<typeof vi.fn>;
  19 +};
  20 +
  21 +describe('usrApi', () => {
  22 + beforeEach(() => {
  23 + vi.clearAllMocks();
  24 + });
  25 +
  26 + it('login posts to /usr/login with sUserName/password/companyId', async () => {
  27 + const result = {
  28 + token: 'tk',
  29 + user: { id: 1, sUserName: 'admin', sUserType: '超级管理员', sLanguage: '中文' },
  30 + };
  31 + mockedRequest.post.mockResolvedValue(result);
  32 + const payload = { sUserName: 'admin', password: 'p', companyId: 9 };
  33 + const ret = await login(payload);
  34 + expect(mockedRequest.post).toHaveBeenCalledWith('/usr/login', payload);
  35 + expect(ret).toEqual(result);
  36 + });
  37 +
  38 + it('fetchCompanies gets /usr/companies and returns list', async () => {
  39 + const list = [
  40 + { id: 1, sCompanyName: '甲公司', sVersion: '标准版' },
  41 + { id: 2, sCompanyName: '乙公司', sVersion: null },
  42 + ];
  43 + mockedRequest.get.mockResolvedValue(list);
  44 + const ret = await fetchCompanies();
  45 + expect(mockedRequest.get).toHaveBeenCalledWith('/usr/companies');
  46 + expect(ret).toEqual(list);
  47 + });
  48 +});
... ...