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:
大壮
2026-04-13 03:47:33 +00:00
parent 4e82f8e1e2
commit 278e507e8a
1310 changed files with 7243 additions and 1248 deletions

View 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;