Files
hzhub/hzhub-portal-employee/src/utils/request.ts
大壮 c2513849b4 feat: 添加ERP服务和系统服务,完善员工门户功能
## 新增服务模块

### 1. ERP服务 (hzhub-erp)
- 新增独立的ERP数据适配服务
- 支持SQL Server 2008 R2数据源
- 提供动态API配置管理系统
- 包含客户管理、销售数据等业务接口

### 2. 系统服务 (hzhub-system)
- 新增独立的系统管理服务
- 用户、角色、权限、部门、菜单管理
- 租户管理、操作日志、在线用户监控
- 工作流引擎(warm-flow)集成
- 企业微信审批同步功能

### 3. API网关 (hzhub-gateway)
- 新增Spring Cloud Gateway网关服务
- JWT认证、路由分发、限流熔断
- XSS防护、请求日志记录
- 统一入口端口8080

## 后台管理功能增强

### ERP动态API管理
- 新增动态API配置管理界面
- API测试、文档预览、统计监控
- 错误日志查看、缓存管理
- 从数据库表自动导入API配置

### 系统管理增强
- 企业微信配置管理
- 企业微信审批同步配置
- 部门和用户管理优化

## 员工门户功能完善

### 业务页面
- 审批中心:工作流审批、待办任务
- CRM管理:客户关系管理
- 经销商管理:经销商数据展示
- 供应链管理:采购、库存、销售
- BI报表:数据可视化分析
- ERP数据探索:SQL Server数据查询

### 个人中心
- 基本设置:个人信息管理
- 安全设置:密码修改、登录日志
- 锁屏功能:自动锁屏、手动锁屏

### 其他功能
- 标签页管理:多标签页导航
- 页面缓存:keepAlive缓存机制
- 会话超时:自动检测并提示

## 经销商门户

### 页面路由
- 新增经销商管理页面路由
- AI聊天界面完善

## 文档更新

- ERP API数据库初始化指南
- ERP API前端完整实现文档
- ERP API测试和验证指南
- Gateway路由迁移计划
- 项目配置文档更新

## 部署脚本

- 统一启动/停止/重启脚本
- Docker Compose配置优化
- Nginx配置文件更新

## 技术栈

- 后端: Spring Boot 3.5.8, Java 17
- 前端: Vue 3, TypeScript, Element Plus, Vben Admin
- 工作流: warm-flow 1.8.2
- 网关: Spring Cloud Gateway
- 数据库: MySQL 8.0, SQL Server 2008 R2
- 缓存: Redis 7
- 向量库: Weaviate 1.25.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 08:00:19 +00:00

125 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { HookFetchPlugin } from 'hook-fetch';
import { ElMessage } from 'element-plus';
import hookFetch from 'hook-fetch';
import { sseTextDecoderPlugin } from 'hook-fetch/plugins';
import { useUserStore } from '@/stores';
interface BaseResponse {
code: number;
data?: any;
msg: string;
rows?: any;
total?: number;
}
export const request = hookFetch.create<BaseResponse, 'data' | 'rows'>({
baseURL: import.meta.env.VITE_API_URL,
headers: {
'Content-Type': 'application/json',
},
plugins: [sseTextDecoderPlugin({ json: true, prefix: 'data:' })],
});
// 错误信息翻译映射
const errorMessageMap: Record<string, string> = {
'Password input error': '密码输入错误',
'User does not exist': '用户不存在',
'User is not exist': '用户不存在',
'Invalid username or password': '用户名或密码错误',
'Account has been locked': '账号已被锁定',
'Account has been disabled': '账号已被禁用',
'Login expired': '登录已过期',
'no basic auth': '未登录',
};
// 翻译错误信息
function translateError(msg: string): string {
if (!msg)
return '请求失败';
// 精确匹配
if (errorMessageMap[msg]) {
return errorMessageMap[msg];
}
// 部分匹配(处理类似 "Password input error 1 times" 的情况)
for (const [key, value] of Object.entries(errorMessageMap)) {
if (msg.includes(key)) {
// 提取数字(如错误次数)
const match = msg.match(/\d+/);
if (match) {
return `${value} ${match[0]}`;
}
return value;
}
}
// 没有匹配的翻译,返回原始消息
return msg;
}
function jwtPlugin(): HookFetchPlugin<BaseResponse> {
const userStore = useUserStore();
return {
name: 'jwt',
beforeRequest: async (config) => {
config.headers = new Headers(config.headers);
config.headers.set('authorization', `Bearer ${userStore.token}`);
config.headers.set('ClientID', import.meta.env.VITE_CLIENT_ID);
// 添加租户ID到请求头
if (userStore.userInfo?.tenantId) {
config.headers.set('tenant-id', userStore.userInfo.tenantId);
}
return config;
},
afterResponse: async (response) => {
const resp = response.response;
// 判断 result 是否已被解析为对象(非 Response
const body = (response.result && !(response.result instanceof Response))
? response.result
: (resp?.ok ? await resp.json() : await resp.clone().json());
if (!resp?.ok) {
const errorMsg = translateError(body?.msg);
if (body?.code === 401) {
userStore.logout();
}
ElMessage.error(errorMsg || '请求失败');
return Promise.reject(response);
}
response.result = body;
if (body?.code === 200) {
// 返回完整的响应对象,包含 code, data, msg
// 前端代码需要从 result.data 中提取实际数据
return response;
}
const errorMsg = translateError(body?.msg);
if (body?.code === 403) {
return Promise.reject(response);
}
if (body?.code === 401) {
userStore.logout();
ElMessage.error(errorMsg || '登录已过期,请重新登录');
return Promise.reject(response);
}
ElMessage.error(errorMsg || '请求失败');
return Promise.reject(response);
},
};
}
request.use(jwtPlugin());
export const post = request.post;
export const get = request.get;
export const put = request.put;
export const del = request.delete;
export default request;