Files
TERES_web_frontend/src/hooks/setting-hooks.ts
guangfei.zhao 83df8a7373 feat(auth): enhance password change flow and error handling
- Return response from useProfileSetting hook after password change
2025-11-19 17:43:45 +08:00

528 lines
16 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 { useUserData } from "./useUserData";
import { useEffect, useState, useCallback } from "react";
import logger from "@/utils/logger";
import type { IUserInfo, ISystemStatus } from "@/interfaces/database/user-setting";
import userService from "@/services/user_service";
import { rsaPsw } from "../utils/encryption";
import type { IFactory, IMyLlmModel } from "@/interfaces/database/llm";
import type { LLMFactory } from "@/constants/llm";
import type { IMcpServer, IMcpServerListResponse } from "@/interfaces/database/mcp";
import type { IImportMcpServersRequestBody, ITestMcpRequestBody, ICreateMcpServerRequestBody } from "@/interfaces/request/mcp";
import type { IPaginationBody } from "@/interfaces/request/base";
import { LanguageAbbreviation, LanguageAbbreviationKeysMap, LanguageTranslationMap } from "@/constants/common";
/**
* 个人中心设置
*/
export function useProfileSetting() {
const { fetchUserInfo, userInfo } = useUserData();
useEffect(() => {
// 仅在已登录情况下才获取用户信息避免登录页触发401导致重复跳转
const authorization = localStorage.getItem('Authorization');
if (authorization && authorization !== '') {
fetchUserInfo();
}
}, [fetchUserInfo]);
const updateUserInfo = async (newUserInfo: Partial<IUserInfo>) => {
try {
await userService.updateSetting(newUserInfo);
} catch (error) {
logger.error('更新用户信息失败:', error);
throw error;
}
};
const changeUserPassword = async (data: { password: string; new_password: string }) => {
try {
const newPassword = rsaPsw(data.new_password);
const oldPassword = rsaPsw(data.password);
const res = await userService.updatePassword({
password: oldPassword,
new_password: newPassword,
});
return res;
} catch (error) {
throw error;
}
};
return {
userInfo,
updateUserInfo,
changeUserPassword,
};
}
export function useLanguageSetting() {
const { userInfo, updateUserInfo } = useProfileSetting();
const [language, setLanguage] = useState(userInfo?.language || 'English');
const changeLanguage = async (language: LanguageAbbreviation) => {
try {
// LanguageAbbreviation to language
const translatedLanguage = LanguageAbbreviationKeysMap[language];
const authorization = localStorage.getItem('Authorization');
// 未登录时仅本地切换语言不请求后端避免401导致跳转
if (!authorization || authorization === '') {
setLanguage(translatedLanguage);
return;
}
await updateUserInfo({ language: translatedLanguage });
setLanguage(translatedLanguage);
} catch (error) {
logger.error('更新语言设置失败:', error);
throw error;
}
}
return {
language,
changeLanguage,
}
}
/**
* LLM 模型设置
*/
export function useLlmModelSetting() {
const [llmFactory, setLlmFactory] = useState<IFactory[]>([]);
const [myLlm, setMyLlm] = useState<Record<LLMFactory, IMyLlmModel>>();
const fetchLlmFactory = async () => {
try {
const res = await userService.llm_factories_list();
const arr = res.data.data || [];
setLlmFactory(arr);
} catch (error) {
logger.error('获取模型工厂失败:', error);
throw error;
}
}
const fetchMyLlm = async () => {
try {
const res = await userService.my_llm({include_details: true});
const llm_dic = res.data.data || {};
setMyLlm(llm_dic);
} catch (error) {
logger.error('获取我的模型失败:', error);
throw error;
}
}
useEffect(() => {
fetchLlmFactory();
fetchMyLlm();
}, []);
const refreshLlmModel = async () => {
await fetchMyLlm();
// await fetchLlmFactory();
logger.info('刷新我的模型成功');
}
return {
llmFactory,
myLlm,
refreshLlmModel,
}
}
/**
* 系统状态设置
*/
export function useSystemStatus() {
const [systemStatus, setSystemStatus] = useState<ISystemStatus | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const fetchSystemStatus = useCallback(async () => {
try {
setLoading(true);
setError(null);
const res = await userService.system_status();
if (res.data.code === 0) {
setSystemStatus(res.data.data);
} else {
throw new Error(res.data.message || '获取系统状态失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '获取系统状态失败';
setError(errorMessage);
logger.error('获取系统状态失败:', error);
} finally {
setLoading(false);
}
}, []);
return {
systemStatus,
loading,
error,
fetchSystemStatus,
};
}
/**
* 团队设置
*/
export function useTeamSetting() {
const { userInfo, tenantInfo, tenantList, refreshUserData } = useUserData();
const [tenantUsers, setTenantUsers] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// 获取租户用户列表
const fetchTenantUsers = useCallback(async () => {
if (!tenantInfo?.tenant_id) return;
try {
const response = await userService.listTenantUser(tenantInfo.tenant_id);
if (response.data.code === 0) {
setTenantUsers(response.data.data || []);
}
} catch (error) {
logger.error('获取租户用户失败:', error);
}
}, [tenantInfo?.tenant_id]);
useEffect(() => {
if (tenantInfo?.tenant_id) {
fetchTenantUsers();
}
}, [fetchTenantUsers]);
const inviteUser = async (email: string) => {
if (!email.trim() || !tenantInfo?.tenant_id) return;
setLoading(true);
setError(null);
try {
const response = await userService.addTenantUser(tenantInfo.tenant_id, email.trim());
if (response.data.code === 0) {
await fetchTenantUsers();
await refreshUserData();
return { success: true };
} else {
const errorMsg = response.data.message || '邀请失败';
setError(errorMsg);
return { success: false, error: errorMsg };
}
} catch (error: any) {
const errorMsg = error.message || '邀请失败';
setError(errorMsg);
return { success: false, error: errorMsg };
} finally {
setLoading(false);
}
};
const deleteUser = async (userId: string) => {
if (!tenantInfo?.tenant_id) return;
try {
const response = await userService.deleteTenantUser({
tenantId: tenantInfo.tenant_id,
userId
});
if (response.data.code === 0) {
await fetchTenantUsers();
return { success: true };
}
return { success: false };
} catch (error) {
logger.error('删除用户失败:', error);
return { success: false };
}
};
const agreeTenant = async (tenantId: string) => {
try {
const response = await userService.agreeTenant(tenantId);
if (response.data.code === 0) {
await refreshUserData();
return { success: true };
}
return { success: false };
} catch (error) {
logger.error('同意加入失败:', error);
return { success: false };
}
};
const quitTenant = async (tenantId: string) => {
if (!userInfo?.id) return;
try {
const response = await userService.deleteTenantUser({
tenantId,
userId: userInfo.id
});
if (response.data.code === 0) {
await refreshUserData();
return { success: true };
}
return { success: false };
} catch (error) {
logger.error('退出租户失败:', error);
return { success: false };
}
};
return {
userInfo,
tenantInfo,
tenantList,
tenantUsers,
loading,
error,
inviteUser,
deleteUser,
agreeTenant,
quitTenant,
refreshUserData,
};
}
/**
* MCP 设置
*/
export function useMcpSetting({ refreshServer }: { refreshServer: (initial?: boolean) => Promise<void> }) {
const [mcpServers, setMcpServers] = useState<IMcpServer[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [total, setTotal] = useState(0);
// 获取 MCP 服务器列表
const fetchMcpServers = useCallback(async (params?: IPaginationBody & {
keyword?: string;
}) => {
try {
setLoading(true);
setError(null);
const res = await userService.listMcpServer({
page: params?.page || 1,
size: params?.size || 8,
keyword: params?.keyword,
});
if (res.data.code === 0) {
const data: IMcpServerListResponse = res.data.data;
setMcpServers(data.mcp_servers || []);
setTotal(data.total || 0);
} else {
throw new Error(res.data.message || '获取 MCP 服务器列表失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '获取 MCP 服务器列表失败';
setError(errorMessage);
logger.error('获取 MCP 服务器列表失败:', error);
} finally {
setLoading(false);
}
}, []);
// 导入 MCP 服务器
const importMcpServers = useCallback(async (data: IImportMcpServersRequestBody) => {
try {
setLoading(true);
setError(null);
const res = await userService.importMcpServer(data);
if (res.data.code === 0) {
await refreshServer();
return { success: true };
} else {
throw new Error(res.data.message || '导入 MCP 服务器失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '导入 MCP 服务器失败';
setError(errorMessage);
logger.error('导入 MCP 服务器失败:', error);
return { success: false, error: errorMessage };
} finally {
setLoading(false);
}
}, []);
// 导出 MCP 服务器
const exportMcpServers = useCallback(async (mcpIds: string[]) => {
try {
setLoading(true);
setError(null);
const res = await userService.exportMcpServer(mcpIds);
if (res.data.code === 0) {
// 处理导出数据,创建下载
const exportData = res.data.data;
const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'mcp-servers.json';
a.click();
URL.revokeObjectURL(url);
return { success: true };
} else {
throw new Error(res.data.message || '导出 MCP 服务器失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '导出 MCP 服务器失败';
setError(errorMessage);
logger.error('导出 MCP 服务器失败:', error);
return { success: false, error: errorMessage };
} finally {
setLoading(false);
}
}, []);
// 测试 MCP 服务器
const testMcpServer = useCallback(async (data: ITestMcpRequestBody) => {
try {
setLoading(true);
setError(null);
const res = await userService.testMcpServer(data);
if (res.data.code === 0) {
return { success: true, data: res.data.data };
} else {
throw new Error(res.data.message || '测试 MCP 服务器失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '测试 MCP 服务器失败';
setError(errorMessage);
return { success: false, error: errorMessage };
} finally {
setLoading(false);
}
}, []);
// 获取 MCP 服务器详情
const getMcpServerDetail = useCallback(async (mcpId: string) => {
try {
setLoading(true);
setError(null);
const res = await userService.mcpDetail(mcpId);
if (res.data.code === 0) {
const detail: IMcpServer = res.data.data;
return { success: true, data: detail };
} else {
throw new Error(res.data.message || '获取 MCP 服务器详情失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '获取 MCP 服务器详情失败';
setError(errorMessage);
logger.error('获取 MCP 服务器详情失败:', error);
return { success: false, error: errorMessage };
} finally {
setLoading(false);
}
}, []);
// 创建 MCP 服务器
const createMcpServer = useCallback(async (data: ICreateMcpServerRequestBody) => {
try {
setLoading(true);
setError(null);
const res = await userService.createMcpServer(data);
if (res.data.code === 0) {
await refreshServer(true); // 重新获取列表
return { success: true, data: res.data.data };
} else {
throw new Error(res.data.message || '创建 MCP 服务器失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '创建 MCP 服务器失败';
setError(errorMessage);
logger.error('创建 MCP 服务器失败:', error);
return { success: false, error: errorMessage };
} finally {
setLoading(false);
}
}, []);
// 更新 MCP 服务器
const updateMcpServer = useCallback(async (data: ICreateMcpServerRequestBody & { mcp_id: string }) => {
try {
setLoading(true);
setError(null);
const res = await userService.updateMcpServer(data);
if (res.data.code === 0) {
await refreshServer(); // 刷新列表
return { success: true, data: res.data.data };
} else {
throw new Error(res.data.message || '更新 MCP 服务器失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '更新 MCP 服务器失败';
setError(errorMessage);
logger.error('更新 MCP 服务器失败:', error);
return { success: false, error: errorMessage };
} finally {
setLoading(false);
}
}, []);
// 删除 MCP 服务器
const deleteMcpServer = useCallback(async (mcpId: string) => {
try {
setLoading(true);
setError(null);
const res = await userService.removeMcpServer([mcpId]);
if (res.data.code === 0) {
await refreshServer(); // 刷新列表
return { success: true };
} else {
throw new Error(res.data.message || '删除 MCP 服务器失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '删除 MCP 服务器失败';
setError(errorMessage);
logger.error('删除 MCP 服务器失败:', error);
return { success: false, error: errorMessage };
} finally {
setLoading(false);
}
}, []);
// 批量删除 MCP 服务器
const batchDeleteMcpServers = useCallback(async (mcpIds: string[]) => {
try {
setLoading(true);
setError(null);
const res = await userService.removeMcpServer(mcpIds);
if (res.data.code === 0) {
await fetchMcpServers(); // 重新获取列表
return { success: true };
} else {
throw new Error(res.data.message || '批量删除 MCP 服务器失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '批量删除 MCP 服务器失败';
setError(errorMessage);
logger.error('批量删除 MCP 服务器失败:', error);
return { success: false, error: errorMessage };
} finally {
setLoading(false);
}
}, []);
return {
// 状态
mcpServers,
loading,
error,
total,
// 方法
fetchMcpServers,
importMcpServers,
exportMcpServers,
testMcpServer,
getMcpServerDetail,
createMcpServer,
updateMcpServer,
deleteMcpServer,
batchDeleteMcpServers,
};
}