优化使用体验
This commit is contained in:
+47
-20
@@ -1,11 +1,10 @@
|
||||
import { type LoaderFunctionArgs, redirect } from "@remix-run/node";
|
||||
import { OAuthClient } from "~/api/login/oauth-client";
|
||||
import { OAUTH_CONFIG } from "~/config/api-config";
|
||||
import { createUserSession, saveUserInfo } from "~/api/login/auth.server";
|
||||
import { JWTUtils, type UserInfoForJWT } from "~/utils/jwt";
|
||||
|
||||
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 code = url.searchParams.get("code");
|
||||
const state = url.searchParams.get("state");
|
||||
const error = url.searchParams.get("error");
|
||||
@@ -42,28 +41,56 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
try {
|
||||
console.log("🔧 开始处理OAuth2.0回调");
|
||||
|
||||
// 创建OAuth客户端
|
||||
const oauthClient = new OAuthClient(OAUTH_CONFIG);
|
||||
console.log("✅ OAuth客户端创建成功");
|
||||
// --- 修改开始: 不再直接调用OAuthClient,而是通过内部代理API ---
|
||||
|
||||
// 获取访问令牌
|
||||
console.log("🔧 开始获取访问令牌...");
|
||||
const tokenResponse = await oauthClient.getAccessToken(code);
|
||||
if (!tokenResponse) {
|
||||
console.error("❌ 获取访问令牌失败");
|
||||
return redirect("/login?error=token_error");
|
||||
}
|
||||
console.log("✅ 访问令牌获取成功");
|
||||
// 获取访问令牌 (通过代理)
|
||||
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 userInfo = await oauthClient.getUserInfo(tokenResponse.access_token);
|
||||
if (!userInfo || !userInfo.success) {
|
||||
console.error("获取用户信息失败:", userInfo);
|
||||
return redirect("/login?error=userinfo_error");
|
||||
const tokenResponse = await proxyResponse.json();
|
||||
|
||||
if (!proxyResponse.ok || !tokenResponse.success) {
|
||||
console.error("❌ [Callback] 通过内部代理获取访问令牌失败:", tokenResponse);
|
||||
return redirect("/login?error=token_proxy_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 redirect("/login?error=userinfo_proxy_error");
|
||||
}
|
||||
|
||||
// 将代理返回的用户信息包装成与原有一致的结构
|
||||
const userInfo = {
|
||||
success: true,
|
||||
data: userInfoResponse.data,
|
||||
};
|
||||
// --- 修改结束 ---
|
||||
|
||||
console.log("✅ [Callback] 用户信息获取成功");
|
||||
|
||||
// TODO 根据用户信息判断用户角色,这里可以根据实际业务逻辑调整 暂定都是common
|
||||
// const userRole = userInfo.data.username === "admin" ? "developer" : "common";
|
||||
const userRole = "common";
|
||||
|
||||
// 获取重定向URL
|
||||
@@ -91,7 +118,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
ou_id: savedUserData.ou_id,
|
||||
ou_name: savedUserData.ou_name,
|
||||
is_leader: savedUserData.is_leader,
|
||||
user_role: userRole
|
||||
user_role: userRole as 'common' | 'developer'
|
||||
};
|
||||
|
||||
const frontendJWT = JWTUtils.generateJWT(jwtUserInfo, tokenResponse.expires_in);
|
||||
|
||||
@@ -172,7 +172,7 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
}, { status: 500 });
|
||||
}
|
||||
|
||||
// console.log('用户任务详情返回:', response.data);
|
||||
console.log('用户任务详情返回:', response.data);
|
||||
return Response.json({
|
||||
success: true,
|
||||
data: response.data
|
||||
|
||||
@@ -192,6 +192,26 @@ export default function DocumentsIndex() {
|
||||
// 添加一个状态来跟踪是否执行了删除操作
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
// 查询参数记忆 key 与保存/恢复方法
|
||||
const SEARCH_PARAMS_STORAGE_KEY = 'documents.searchParams';
|
||||
const persistSearchParams = (params: URLSearchParams) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.setItem(SEARCH_PARAMS_STORAGE_KEY, params.toString());
|
||||
}
|
||||
};
|
||||
|
||||
// 首次进入且 URL 无任何查询参数时,尝试从 sessionStorage 恢复
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
const hasAnyParam = Array.from(searchParams.keys()).length > 0;
|
||||
const stored = sessionStorage.getItem(SEARCH_PARAMS_STORAGE_KEY);
|
||||
if (!hasAnyParam && stored) {
|
||||
setSearchParams(new URLSearchParams(stored));
|
||||
}
|
||||
// 仅初始化检查一次
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// 从URL获取当前筛选条件
|
||||
const search = searchParams.get("search") || "";
|
||||
const documentType = searchParams.get("documentType") || "";
|
||||
@@ -202,7 +222,7 @@ export default function DocumentsIndex() {
|
||||
const dateTo = searchParams.get("dateTo") || "";
|
||||
const currentPage = parseInt(searchParams.get("page") || "1", 10);
|
||||
const pageSize = parseInt(searchParams.get("pageSize") || "10", 10);
|
||||
|
||||
|
||||
// 客户端数据请求
|
||||
const fetchData = useCallback(async (storedReviewType: string) => {
|
||||
setIsLoadingData(true);
|
||||
@@ -323,15 +343,19 @@ export default function DocumentsIndex() {
|
||||
|
||||
// 分页处理函数
|
||||
const handlePageChange = (page: number) => {
|
||||
searchParams.set("page", page.toString());
|
||||
setSearchParams(searchParams);
|
||||
const params = new URLSearchParams(searchParams);
|
||||
params.set("page", page.toString());
|
||||
persistSearchParams(params);
|
||||
setSearchParams(params);
|
||||
};
|
||||
|
||||
// 每页条数变更处理函数
|
||||
const handlePageSizeChange = (size: number) => {
|
||||
searchParams.set("pageSize", size.toString());
|
||||
searchParams.set("page", "1"); // 重置到第一页
|
||||
setSearchParams(searchParams);
|
||||
const params = new URLSearchParams(searchParams);
|
||||
params.set("pageSize", size.toString());
|
||||
params.set("page", "1"); // 重置到第一页
|
||||
persistSearchParams(params);
|
||||
setSearchParams(params);
|
||||
};
|
||||
|
||||
// 处理文档名称搜索
|
||||
@@ -343,6 +367,7 @@ export default function DocumentsIndex() {
|
||||
params.delete("search");
|
||||
}
|
||||
params.set("page", "1"); // 重置页码
|
||||
persistSearchParams(params);
|
||||
setSearchParams(params);
|
||||
};
|
||||
|
||||
@@ -355,6 +380,7 @@ export default function DocumentsIndex() {
|
||||
params.delete("documentNumber");
|
||||
}
|
||||
params.set("page", "1"); // 重置页码
|
||||
persistSearchParams(params);
|
||||
setSearchParams(params);
|
||||
};
|
||||
|
||||
@@ -367,6 +393,7 @@ export default function DocumentsIndex() {
|
||||
params.delete("documentType");
|
||||
}
|
||||
params.set("page", "1"); // 重置页码
|
||||
persistSearchParams(params);
|
||||
setSearchParams(params);
|
||||
};
|
||||
|
||||
@@ -379,6 +406,7 @@ export default function DocumentsIndex() {
|
||||
params.delete("auditStatus");
|
||||
}
|
||||
params.set("page", "1"); // 重置页码
|
||||
persistSearchParams(params);
|
||||
setSearchParams(params);
|
||||
};
|
||||
|
||||
@@ -391,6 +419,7 @@ export default function DocumentsIndex() {
|
||||
params.delete(field);
|
||||
}
|
||||
params.set("page", "1"); // 重置页码
|
||||
persistSearchParams(params);
|
||||
setSearchParams(params);
|
||||
};
|
||||
|
||||
@@ -419,7 +448,10 @@ export default function DocumentsIndex() {
|
||||
resetInput('input[name="dateFrom"]');
|
||||
resetInput('input[name="dateTo"]');
|
||||
|
||||
// 重置URL参数
|
||||
// 重置URL参数并清除保存
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.removeItem(SEARCH_PARAMS_STORAGE_KEY);
|
||||
}
|
||||
setSearchParams(new URLSearchParams({
|
||||
page: "1",
|
||||
pageSize: pageSize.toString()
|
||||
@@ -681,8 +713,10 @@ export default function DocumentsIndex() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// console.log('更新成功,开始跳转')
|
||||
// 导航到评查详情页
|
||||
// 导航到评查详情页前保存查询参数
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.setItem(SEARCH_PARAMS_STORAGE_KEY, searchParams.toString());
|
||||
}
|
||||
navigate(`/reviews?id=${fileId}&previousRoute=documents`);
|
||||
};
|
||||
|
||||
|
||||
@@ -102,6 +102,27 @@ export default function RulesFiles() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [reviewType, setReviewType] = useState<string | null>(null);
|
||||
|
||||
// 保存/恢复 查询参数 的 sessionStorage key
|
||||
const SEARCH_PARAMS_STORAGE_KEY = 'rulesFiles.searchParams';
|
||||
|
||||
const persistSearchParams = useCallback((params: URLSearchParams) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.setItem(SEARCH_PARAMS_STORAGE_KEY, params.toString());
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 首次进入列表页且 URL 无查询参数时,尝试恢复上次保存的参数
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
const hasAnyParam = Array.from(searchParams.keys()).length > 0;
|
||||
const stored = sessionStorage.getItem(SEARCH_PARAMS_STORAGE_KEY);
|
||||
if (!hasAnyParam && stored) {
|
||||
setSearchParams(new URLSearchParams(stored));
|
||||
}
|
||||
// 仅在初始渲染时检查
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// 处理初始加载数据loader的错误
|
||||
useEffect(() => {
|
||||
if(result === false && message) {
|
||||
@@ -254,6 +275,7 @@ export default function RulesFiles() {
|
||||
// 切换筛选条件时,重置到第一页
|
||||
newParams.set('page', '1');
|
||||
|
||||
persistSearchParams(newParams);
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
@@ -269,6 +291,7 @@ export default function RulesFiles() {
|
||||
// 搜索时,重置到第一页
|
||||
newParams.set('page', '1');
|
||||
|
||||
persistSearchParams(newParams);
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
@@ -276,6 +299,7 @@ export default function RulesFiles() {
|
||||
const handlePageChange = (page: number) => {
|
||||
const newParams = new URLSearchParams(searchParams);
|
||||
newParams.set('page', page.toString());
|
||||
persistSearchParams(newParams);
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
@@ -284,6 +308,7 @@ export default function RulesFiles() {
|
||||
const newParams = new URLSearchParams(searchParams);
|
||||
newParams.set('pageSize', size.toString());
|
||||
newParams.set('page', '1'); // 改变每页条数时重置为第一页
|
||||
persistSearchParams(newParams);
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
@@ -311,6 +336,10 @@ export default function RulesFiles() {
|
||||
}
|
||||
|
||||
// 导航到评查详情页
|
||||
// 在离开当前页前保存当前查询参数,返回时可恢复
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.setItem(SEARCH_PARAMS_STORAGE_KEY, searchParams.toString());
|
||||
}
|
||||
navigate(`/reviews?id=${fileId}&previousRoute=rulesFiles`);
|
||||
};
|
||||
|
||||
@@ -412,6 +441,9 @@ export default function RulesFiles() {
|
||||
if(searchInput) {
|
||||
(searchInput as HTMLInputElement).value = '';
|
||||
}
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.removeItem(SEARCH_PARAMS_STORAGE_KEY);
|
||||
}
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
|
||||
@@ -188,6 +188,26 @@ export default function RulesIndex() {
|
||||
// 添加一个状态来跟踪是否执行了删除操作
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
// 查询参数记忆 key 与保存/恢复
|
||||
const SEARCH_PARAMS_STORAGE_KEY = 'rules.searchParams';
|
||||
const persistSearchParams = (params: URLSearchParams) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.setItem(SEARCH_PARAMS_STORAGE_KEY, params.toString());
|
||||
}
|
||||
};
|
||||
|
||||
// 首次进入页且 URL 无参数时尝试恢复
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
const hasAnyParam = Array.from(searchParams.keys()).length > 0;
|
||||
const stored = sessionStorage.getItem(SEARCH_PARAMS_STORAGE_KEY);
|
||||
if (!hasAnyParam && stored) {
|
||||
setSearchParams(new URLSearchParams(stored));
|
||||
}
|
||||
// 仅初始化检查一次
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// 获取当前的ruleType值
|
||||
const ruleTypeParam = searchParams.get('ruleType');
|
||||
|
||||
@@ -416,7 +436,7 @@ export default function RulesIndex() {
|
||||
|
||||
// 切换筛选条件时,重置到第一页
|
||||
newParams.set('page', '1');
|
||||
|
||||
persistSearchParams(newParams);
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
@@ -431,7 +451,7 @@ export default function RulesIndex() {
|
||||
|
||||
// 搜索时,重置到第一页
|
||||
newParams.set('page', '1');
|
||||
|
||||
persistSearchParams(newParams);
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
@@ -463,6 +483,7 @@ export default function RulesIndex() {
|
||||
const handlePageChange = (page: number) => {
|
||||
const newParams = new URLSearchParams(searchParams);
|
||||
newParams.set('page', page.toString());
|
||||
persistSearchParams(newParams);
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
@@ -471,6 +492,7 @@ export default function RulesIndex() {
|
||||
const newParams = new URLSearchParams(searchParams);
|
||||
newParams.set('pageSize', size.toString());
|
||||
newParams.set('page', '1'); // 更改每页条数时,重置到第一页
|
||||
persistSearchParams(newParams);
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
@@ -482,6 +504,9 @@ export default function RulesIndex() {
|
||||
}
|
||||
// 保留reviewType的过滤条件,只重置其他条件
|
||||
const newParams = new URLSearchParams();
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.removeItem(SEARCH_PARAMS_STORAGE_KEY);
|
||||
}
|
||||
setSearchParams(newParams);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user