feat: 添加员工门户项目及相关后端改造
- 新增 hzhub-portal-employee 员工门户前端项目(基于 Vue3 + Element Plus) - 后端登录接口增加返回 nickName 字段 - 移除 KnowledgeInfoController 的 @SaCheckPermission 注解 - 删除 hzhub-portal-company 旧门户项目 - 更新项目文档和架构说明 - 添加后台运行管理脚本(start-all.sh / status-all.sh / stop-all.sh) - 更新 docker-compose 配置 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
114
hzhub-portal-employee/src/utils/request.ts
Normal file
114
hzhub-portal-employee/src/utils/request.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
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: never;
|
||||
msg: string;
|
||||
rows: never;
|
||||
}
|
||||
|
||||
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) => {
|
||||
// console.log(response);
|
||||
|
||||
// 成功响应
|
||||
if (response.result?.code === 200) {
|
||||
return response;
|
||||
}
|
||||
|
||||
const errorMsg = translateError(response.result?.msg);
|
||||
|
||||
// 处理403:静默拒绝,由业务代码自行处理
|
||||
if (response.result?.code === 403) {
|
||||
return Promise.reject(response);
|
||||
}
|
||||
|
||||
// 处理401逻辑
|
||||
if (response.result?.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;
|
||||
Reference in New Issue
Block a user