feat(user): add user data management system with global state
- Implement user store with Zustand for global state management - Create UserDataProvider component to initialize user data on app load - Add useUserData hook for accessing and managing user data - Refactor knowledge base list page to use new hooks
This commit is contained in:
197
src/hooks/knowledge_hooks.ts
Normal file
197
src/hooks/knowledge_hooks.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import knowledgeService from '@/services/knowledge_service';
|
||||
import type { IKnowledge } from '@/interfaces/database/knowledge';
|
||||
|
||||
// 知识库列表查询参数接口
|
||||
export interface KnowledgeListParams {
|
||||
keywords?: string;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}
|
||||
|
||||
// 知识库列表响应接口
|
||||
export interface KnowledgeListResponse {
|
||||
kbs: IKnowledge[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
// 知识库列表Hook状态接口
|
||||
export interface UseKnowledgeListState {
|
||||
knowledgeBases: IKnowledge[];
|
||||
total: number;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
keywords: string;
|
||||
}
|
||||
|
||||
// 知识库列表Hook返回值接口
|
||||
export interface UseKnowledgeListReturn extends UseKnowledgeListState {
|
||||
fetchKnowledgeBases: (params?: KnowledgeListParams) => Promise<void>;
|
||||
setKeywords: (keywords: string) => void;
|
||||
setCurrentPage: (page: number) => void;
|
||||
setPageSize: (size: number) => void;
|
||||
refresh: () => Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 知识库列表数据管理Hook
|
||||
* 支持关键词搜索、分页等功能
|
||||
*/
|
||||
export const useKnowledgeList = (
|
||||
initialParams?: KnowledgeListParams
|
||||
): UseKnowledgeListReturn => {
|
||||
const [knowledgeBases, setKnowledgeBases] = useState<IKnowledge[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [currentPage, setCurrentPage] = useState(initialParams?.page || 1);
|
||||
const [pageSize, setPageSize] = useState(initialParams?.page_size || 10);
|
||||
const [keywords, setKeywords] = useState(initialParams?.keywords || '');
|
||||
|
||||
/**
|
||||
* 获取知识库列表
|
||||
*/
|
||||
const fetchKnowledgeBases = useCallback(async (params?: KnowledgeListParams) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
// 合并参数
|
||||
const queryParams = {
|
||||
keywords: params?.keywords ?? keywords,
|
||||
page: params?.page ?? currentPage,
|
||||
page_size: params?.page_size ?? pageSize,
|
||||
};
|
||||
|
||||
// 构建请求体
|
||||
const requestBody: any = {};
|
||||
if (queryParams.keywords) {
|
||||
requestBody.keywords = queryParams.keywords;
|
||||
}
|
||||
|
||||
// 构建查询参数
|
||||
const requestParams: any = {};
|
||||
if (queryParams.page) {
|
||||
requestParams.page = queryParams.page;
|
||||
}
|
||||
if (queryParams.page_size) {
|
||||
requestParams.page_size = queryParams.page_size;
|
||||
}
|
||||
|
||||
const response = await knowledgeService.getKnowledgeList(
|
||||
Object.keys(requestParams).length > 0 ? requestParams : undefined,
|
||||
Object.keys(requestBody).length > 0 ? requestBody : undefined
|
||||
);
|
||||
|
||||
// 检查响应状态
|
||||
if (response.data.code === 0) {
|
||||
const data = response.data.data as KnowledgeListResponse;
|
||||
setKnowledgeBases(data.kbs || []);
|
||||
setTotal(data.total || 0);
|
||||
} else {
|
||||
throw new Error(response.data.message || '获取知识库列表失败');
|
||||
}
|
||||
} catch (err: any) {
|
||||
const errorMessage = err.response?.data?.message || err.message || '获取知识库列表失败';
|
||||
setError(errorMessage);
|
||||
console.error('Failed to fetch knowledge bases:', err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [keywords, currentPage, pageSize]);
|
||||
|
||||
/**
|
||||
* 刷新当前页面数据
|
||||
*/
|
||||
const refresh = useCallback(() => {
|
||||
return fetchKnowledgeBases();
|
||||
}, [fetchKnowledgeBases]);
|
||||
|
||||
/**
|
||||
* 设置关键词并重置到第一页
|
||||
*/
|
||||
const handleSetKeywords = useCallback((newKeywords: string) => {
|
||||
setKeywords(newKeywords);
|
||||
setCurrentPage(1);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* 设置当前页
|
||||
*/
|
||||
const handleSetCurrentPage = useCallback((page: number) => {
|
||||
setCurrentPage(page);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* 设置页面大小并重置到第一页
|
||||
*/
|
||||
const handleSetPageSize = useCallback((size: number) => {
|
||||
setPageSize(size);
|
||||
setCurrentPage(1);
|
||||
}, []);
|
||||
|
||||
// 初始化时获取数据
|
||||
useEffect(() => {
|
||||
fetchKnowledgeBases();
|
||||
}, [fetchKnowledgeBases]);
|
||||
|
||||
return {
|
||||
knowledgeBases,
|
||||
total,
|
||||
loading,
|
||||
error,
|
||||
currentPage,
|
||||
pageSize,
|
||||
keywords,
|
||||
fetchKnowledgeBases,
|
||||
setKeywords: handleSetKeywords,
|
||||
setCurrentPage: handleSetCurrentPage,
|
||||
setPageSize: handleSetPageSize,
|
||||
refresh,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 知识库详情Hook
|
||||
*/
|
||||
export const useKnowledgeDetail = (kbId: string) => {
|
||||
const [knowledge, setKnowledge] = useState<IKnowledge | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchKnowledgeDetail = useCallback(async () => {
|
||||
if (!kbId) return;
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const response = await knowledgeService.getKnowledgeDetail({ kb_id: kbId });
|
||||
|
||||
if (response.data.code === 0) {
|
||||
setKnowledge(response.data.data);
|
||||
} else {
|
||||
throw new Error(response.data.message || '获取知识库详情失败');
|
||||
}
|
||||
} catch (err: any) {
|
||||
const errorMessage = err.response?.data?.message || err.message || '获取知识库详情失败';
|
||||
setError(errorMessage);
|
||||
console.error('Failed to fetch knowledge detail:', err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [kbId]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchKnowledgeDetail();
|
||||
}, [fetchKnowledgeDetail]);
|
||||
|
||||
return {
|
||||
knowledge,
|
||||
loading,
|
||||
error,
|
||||
refresh: fetchKnowledgeDetail,
|
||||
};
|
||||
};
|
||||
154
src/hooks/useUserData.ts
Normal file
154
src/hooks/useUserData.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { useUserStore } from '@/stores/userStore';
|
||||
import userService from '@/services/user_service';
|
||||
|
||||
/**
|
||||
* 用户数据管理Hook
|
||||
* 负责在登录后获取用户相关的全局数据
|
||||
*/
|
||||
export const useUserData = () => {
|
||||
const {
|
||||
userInfo,
|
||||
tenantInfo,
|
||||
tenantList,
|
||||
isLoading,
|
||||
error,
|
||||
setUserInfo,
|
||||
setTenantInfo,
|
||||
setTenantList,
|
||||
setLoading,
|
||||
setError,
|
||||
clearUserData,
|
||||
} = useUserStore();
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
const fetchUserInfo = useCallback(async () => {
|
||||
try {
|
||||
const response = await userService.getUserInfo();
|
||||
if (response.data.code === 0) {
|
||||
setUserInfo(response.data.data);
|
||||
return response.data.data;
|
||||
} else {
|
||||
throw new Error(response.data.message || '获取用户信息失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}, [setUserInfo]);
|
||||
|
||||
/**
|
||||
* 获取租户信息
|
||||
*/
|
||||
const fetchTenantInfo = useCallback(async () => {
|
||||
try {
|
||||
const response = await userService.getTenantInfo();
|
||||
if (response.data.code === 0) {
|
||||
setTenantInfo(response.data.data);
|
||||
return response.data.data;
|
||||
} else {
|
||||
throw new Error(response.data.message || '获取租户信息失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取租户信息失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}, [setTenantInfo]);
|
||||
|
||||
/**
|
||||
* 获取租户列表
|
||||
*/
|
||||
const fetchTenantList = useCallback(async () => {
|
||||
try {
|
||||
const response = await userService.listTenant();
|
||||
if (response.data.code === 0) {
|
||||
setTenantList(response.data.data || []);
|
||||
return response.data.data;
|
||||
} else {
|
||||
throw new Error(response.data.message || '获取租户列表失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取租户列表失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}, [setTenantList]);
|
||||
|
||||
/**
|
||||
* 初始化所有用户数据
|
||||
* 并行请求三个API以提高性能
|
||||
*/
|
||||
const initializeUserData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
// 并行请求三个API
|
||||
const [userInfoResult, tenantInfoResult, tenantListResult] = await Promise.allSettled([
|
||||
fetchUserInfo(),
|
||||
fetchTenantInfo(),
|
||||
fetchTenantList(),
|
||||
]);
|
||||
|
||||
// 检查是否有失败的请求
|
||||
const errors: string[] = [];
|
||||
|
||||
if (userInfoResult.status === 'rejected') {
|
||||
errors.push(`用户信息: ${userInfoResult.reason.message}`);
|
||||
}
|
||||
|
||||
if (tenantInfoResult.status === 'rejected') {
|
||||
errors.push(`租户信息: ${tenantInfoResult.reason.message}`);
|
||||
}
|
||||
|
||||
if (tenantListResult.status === 'rejected') {
|
||||
errors.push(`租户列表: ${tenantListResult.reason.message}`);
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
const errorMessage = `部分数据获取失败: ${errors.join(', ')}`;
|
||||
setError(errorMessage);
|
||||
console.warn(errorMessage);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : '初始化用户数据失败';
|
||||
setError(errorMessage);
|
||||
console.error('初始化用户数据失败:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [fetchUserInfo, fetchTenantInfo, fetchTenantList, setLoading, setError]);
|
||||
|
||||
/**
|
||||
* 刷新用户数据
|
||||
*/
|
||||
const refreshUserData = useCallback(async () => {
|
||||
await initializeUserData();
|
||||
}, [initializeUserData]);
|
||||
|
||||
/**
|
||||
* 清除用户数据
|
||||
*/
|
||||
const logout = useCallback(() => {
|
||||
clearUserData();
|
||||
}, [clearUserData]);
|
||||
|
||||
return {
|
||||
// 状态
|
||||
userInfo,
|
||||
tenantInfo,
|
||||
tenantList,
|
||||
isLoading,
|
||||
error,
|
||||
|
||||
// 方法
|
||||
initializeUserData,
|
||||
refreshUserData,
|
||||
fetchUserInfo,
|
||||
fetchTenantInfo,
|
||||
fetchTenantList,
|
||||
logout,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user