本文档为 Vben Admin 前端项目(WIDESEA_WMSClient_Vben)提供 API 适配层设计参考。
WIDESEA_WMSClient_Vben/
├── src/
│ ├── api/
│ │ ├── client.ts # axios 实例封装
│ │ ├── modules/
│ │ │ ├── user.ts # 用户认证模块
│ │ │ ├── menu.ts # 菜单模块
│ │ │ ├── stock.ts # 库存模块
│ │ │ ├── inbound.ts # 入库模块
│ │ │ ├── outbound.ts # 出库模块
│ │ │ └── check.ts # 盘点模块
│ │ └── index.ts # 统一导出
api/client.ts)import axios from 'axios';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import { useUserStore } from '@/store/modules/user';
import { useAuthStore } from '@/store/modules/auth';
const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:9291';
const client: AxiosInstance = axios.create({
baseURL: BASE_URL,
timeout: 30000,
headers: { 'Content-Type': 'application/json' },
});
// 请求拦截器:注入 Bearer Token
client.interceptors.request.use(
(config) => {
const userStore = useUserStore();
const token = userStore.token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截器:统一错误处理 + 401 token 过期跳转登录
client.interceptors.response.use(
(response: AxiosResponse) => response.data,
async (error) => {
const status = error.response?.status;
const raw = error.response?.data;
// 业务错误码(非 HTTP 状态码)可从 raw.code 判断
if (raw?.code === 401 || status === 401) {
const authStore = useAuthStore();
authStore.logout(true); // true = token 过期被动登出
}
return Promise.reject(error);
}
);
export default client;
| 场景 | 处理方式 |
|---|---|
| 有 Token | Authorization: Bearer <token> 注入请求头 |
| 无 Token | 放行,让后端返回 401 |
| 主动登出 | 清空 token 跳转登录页 |
| 场景 | 处理方式 |
|---|---|
| 2xx 响应 | 返回 response.data |
| HTTP 401 / 业务 code 401 | 调用 authStore.logout(true) 跳转登录 |
| 其他错误 | 抛出异常,由各模块自行处理 |
modules/user.ts)/** 获取验证码,返回 { img: string, uuid: string } */
export function getVerificationCode(): Promise<{ img: string; uuid: string }>;
/** 登录 */
export function login(params: {
userName: string;
password: string;
verificationCode: string;
UUID: string;
}): Promise<{ token: string; expires: number }>;
/** 当前用户信息 */
export function getCurrentUserInfo(): Promise<UserInfo>;
/** 刷新 Token */
export function replaceToken(): Promise<{ token: string; expires: number }>;
modules/menu.ts)/** 获取树形菜单 */
export function getTreeMenu(): Promise<MenuTreeNode[]>;
interface MenuTreeNode {
id: string;
name: string;
path: string;
component?: string;
icon?: string;
children?: MenuTreeNode[];
}
modules/stock.ts)/** 库存列表(分页) */
export function getStockList(params: StockQuery): Promise<PageResult<StockItem>>;
/** 库存详情 */
export function getStockDetail(id: string): Promise<StockItem>;
modules/inbound.ts)/** 入库单列表 */
export function getInboundOrderList(params: InboundQuery): Promise<PageResult<InboundOrder>>;
/** 创建入库单 */
export function createInboundOrder(data: CreateInboundOrder): Promise<{ id: string }>;
/** 提交入库单 */
export function submitInboundOrder(id: string): Promise<void>;
modules/outbound.ts)/** 出库单列表 */
export function getOutboundOrderList(params: OutboundQuery): Promise<PageResult<OutboundOrder>>;
/** 创建出库单 */
export function createOutboundOrder(data: CreateOutboundOrder): Promise<{ id: string }>;
/** 提交出库单 */
export function submitOutboundOrder(id: string): Promise<void>;
modules/check.ts)/** 盘点单列表 */
export function getCheckOrderList(params: CheckQuery): Promise<PageResult<CheckOrder>>;
/** 创建盘点单 */
export function createCheckOrder(data: CreateCheckOrder): Promise<{ id: string }>;
/** 提交盘点单 */
export function submitCheckOrder(id: string): Promise<void>;
/** 分页结果 */
interface PageResult<T> {
items: T[];
total: number;
page: number;
pageSize: number;
}
/** 通用操作结果(无数据返回时) */
interface OpResult {
code: number;
message: string;
}
# .env.development
VITE_API_BASE_URL=http://localhost:9291
# .env.production
VITE_API_BASE_URL=/api
注意: 生产环境使用
/api代理,避免跨域。