fix: 1.将合同模板和交叉评查中的文件下载改用通过后端api进行转发获取文件来下载。 2.修复登录过程中token认证的代码问题。 3.完善api-config文件中不同端口号不同的回调地址配置。

This commit is contained in:
2025-11-07 18:36:15 +08:00
parent 80f05da984
commit b375c35825
5 changed files with 153 additions and 180 deletions
+20 -46
View File
@@ -1,5 +1,7 @@
import { type LoaderFunctionArgs, redirect } from "@remix-run/node";
import { createUserSession, saveUserInfo, sessionStorage } from "~/api/login/auth.server";
import { OAuthClient } from "~/api/login/oauth-client";
import { OAUTH_CONFIG } from "~/config/api-config";
import { JWTUtils, type UserInfoForJWT } from "~/utils/jwt";
/**
@@ -39,7 +41,7 @@ async function redirectToLoginWithError(request: Request, errorMessage: string)
export async function loader({ request }: LoaderFunctionArgs) {
const url = new URL(request.url);
const origin = url.origin; // 获取请求的源 (e.g., "http://10.79.97.17:51703")
// const origin = url.origin; // 获取请求的源 (e.g., "http://10.79.97.17:51703")
const port = url.port; // 获取端口号
const area = getAreaByPort(port); // 根据端口号获取地区
const code = url.searchParams.get("code");
@@ -80,55 +82,25 @@ export async function loader({ request }: LoaderFunctionArgs) {
try {
console.log("🔧 开始处理OAuth2.0回调");
// --- 修改开始: 不再直接调用OAuthClient,而是通过内部代理API ---
const oauthClient = new OAuthClient(OAUTH_CONFIG)
// 获取访问令牌 (通过代理)
console.log(`🔧 [Callback] 开始通过内部代理获取访问令牌... (目标: ${origin}/api/oauth/token)`);
const proxyResponse = await fetch(`${origin}/api/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ code }),
});
const tokenResponse = await proxyResponse.json();
if (!proxyResponse.ok || !tokenResponse.success) {
console.error("❌ [Callback] 通过内部代理获取访问令牌失败:", tokenResponse);
return redirectToLoginWithError(request, "获取访问令牌失败,请重新登录");
// 开始获取访问令牌
const tokenResponse = await oauthClient.getAccessToken(code);
if (!tokenResponse) {
console.error("获取访问令牌失败");
return redirect("/login?error=token_error")
}
// --- 修改结束 ---
console.log("✅ [Callback] 访问令牌获取成功");
// --- 修改开始: 通过内部代理获取用户信息 ---
console.log(`🔧 [Callback] 开始通过内部代理获取用户信息... (目标: ${origin}/api/oauth/userinfo)`);
const userInfoProxyResponse = await fetch(`${origin}/api/oauth/userinfo`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ accessToken: tokenResponse.access_token }),
});
const userInfoResponse = await userInfoProxyResponse.json();
if (!userInfoProxyResponse.ok || !userInfoResponse.success) {
console.error("❌ [Callback] 通过内部代理获取用户信息失败:", userInfoResponse);
return redirectToLoginWithError(request, "获取用户信息失败,请重新登录");
const userInfo = await oauthClient.getUserInfo(tokenResponse.access_token);
if(!userInfo || !userInfo.success){
console.error('获取用户信息失败:',userInfo);
return redirect('/login?error=userinfo_error')
}
// 将代理返回的用户信息包装成与原有一致的结构
const userInfo = {
success: true,
data: userInfoResponse.data,
};
// --- 修改结束 ---
console.log("✅ [Callback] 用户信息获取成功");
// TODO 根据用户信息判断用户角色,这里可以根据实际业务逻辑调整 暂定都是common
const userRole = "common";
@@ -138,14 +110,16 @@ export async function loader({ request }: LoaderFunctionArgs) {
// 先生成一个临时 JWT
const tempUserInfo = {
sub: userInfo.data.sub,
user_id: userInfo.data.user_id || "",
// user_id: userInfo.data.user_id || "",
user_id: "",
username: userInfo.data.username,
nick_name: userInfo.data.nick_name,
nick_name: userInfo.data.nickname,
email: userInfo.data.email,
phone_number: userInfo.data.phone_number,
ou_id: userInfo.data.ou_id,
ou_name: userInfo.data.ou_name,
is_leader: userInfo.data.is_leader,
// is_leader: userInfo.data.is_leader,
is_leader: false,
user_role: userRole as 'common' | 'developer'
};
const tempToken = JWTUtils.generateJWT(tempUserInfo, tokenResponse.expires_in);
@@ -176,7 +150,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
};
const frontendJWT = JWTUtils.generateJWT(jwtUserInfo, tokenResponse.expires_in);
console.log("前端JWT已生成");
// console.log("前端JWT已生成");
// 更新userInfo以包含数据库ID、JWT,并用数据库标准字段覆盖关键属性,确保 nick_name 等存在
const enhancedUserInfo = {
+34 -35
View File
@@ -8,6 +8,9 @@ import { getUserSession } from '~/api/login/auth.server';
// 导入FilePreview组件
import { FilePreview } from '~/components/reviews';
// 导入统一的下载方法和提示服务
import { downloadFile } from '~/api/axios-client';
import { toastService } from '~/components/ui/Toast';
export const links = () => [
{ rel: 'stylesheet', href: styles },
@@ -70,45 +73,41 @@ export default function ContractTemplateDetail() {
navigate(-1);
};
// MinIO下载URL构建函数
const buildDownloadUrl = (filePath: string): string => {
const minioHost = 'http://nas.7bm.co:9000';
const bucketName = 'docauditai';
const cleanPath = filePath.startsWith('/') ? filePath.substring(1) : filePath;
return `${minioHost}/${bucketName}/${cleanPath}`;
};
// 下载文件函数
const downloadFile = async (filePath: string, fileName: string) => {
try {
const downloadUrl = buildDownloadUrl(filePath);
const cleanFileName = fileName.replace(/[<>:"/\\|?*]/g, '_');
const link = document.createElement('a');
link.href = downloadUrl;
link.download = cleanFileName;
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// console.log('开始下载文件:', cleanFileName);
} catch (error) {
console.error('下载文件失败:', error);
alert('下载失败,请稍后重试');
// 使用统一的下载方法(与 rules-files.tsx 相同)
const handleDownload = async () => {
if (!template.file_path) {
toastService.error('文件路径不存在,无法下载');
return;
}
};
const handleDownload = () => {
if (template.file_path) {
try {
// 使用axios封装的下载方法
const blob = await downloadFile(template.file_path);
// 创建Blob URL
const blobUrl = URL.createObjectURL(blob);
// 清理文件名,移除可能导致问题的字符
const fileExtension = template.file_format || 'docx';
const fileName = `${template.title}.${fileExtension}`;
downloadFile(template.file_path, fileName);
} else {
alert('文件路径不存在,无法下载');
const cleanFileName = fileName.replace(/[<>:"/\\|?*]/g, '_');
// 创建一个隐藏的a标签并点击它
const a = document.createElement('a');
a.style.display = 'none';
a.href = blobUrl;
a.download = cleanFileName;
document.body.appendChild(a);
a.click();
// 清理
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(blobUrl);
}, 100);
} catch (error) {
console.error('下载文件失败:', error);
toastService.error(`下载文件失败: ${error instanceof Error ? error.message : '未知错误'}`);
}
};