mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-05-22 00:30:14 +08:00
feat: Support multiple vector database selection, add InMemory and Qdrant adapters, introduce admin dashboard
This commit is contained in:
@@ -1,108 +0,0 @@
|
||||
import React, { createContext, useState, useEffect, useContext, useCallback } from 'react';
|
||||
import { getCurrentUser, isAuthenticated, clearAuthData, getStoredUser } from './index';
|
||||
import type { UserProfile } from './types';
|
||||
import { UserRole } from './types';
|
||||
|
||||
interface AuthContextType {
|
||||
user: UserProfile | null;
|
||||
loading: boolean;
|
||||
authenticated: boolean;
|
||||
authError: string | null;
|
||||
logout: () => void;
|
||||
refreshUser: () => Promise<void>;
|
||||
hasRole: (requiredRole: UserRole) => boolean;
|
||||
}
|
||||
|
||||
const AuthContext = createContext<AuthContextType>({
|
||||
user: null,
|
||||
loading: true,
|
||||
authenticated: false,
|
||||
authError: null,
|
||||
logout: () => {},
|
||||
refreshUser: async () => {},
|
||||
hasRole: () => false
|
||||
});
|
||||
|
||||
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [user, setUser] = useState<UserProfile | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [authError, setAuthError] = useState<string | null>(null);
|
||||
|
||||
const refreshUser = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setAuthError(null);
|
||||
|
||||
try {
|
||||
const isLoggedIn = isAuthenticated();
|
||||
|
||||
if (isLoggedIn) {
|
||||
const storedUser = getStoredUser();
|
||||
if (storedUser) {
|
||||
setUser(storedUser);
|
||||
}
|
||||
|
||||
const response = await getCurrentUser();
|
||||
|
||||
if (response.success && response.data) {
|
||||
setUser(response.data);
|
||||
} else if (!storedUser) {
|
||||
setAuthError(response.message || '获取用户信息失败');
|
||||
clearAuthData();
|
||||
setUser(null);
|
||||
}
|
||||
} else {
|
||||
clearAuthData();
|
||||
setUser(null);
|
||||
}
|
||||
} catch (error: any) {
|
||||
setAuthError(error.message || '获取用户信息时发生错误');
|
||||
if (!getStoredUser()) {
|
||||
clearAuthData();
|
||||
setUser(null);
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const logout = useCallback(() => {
|
||||
clearAuthData();
|
||||
setUser(null);
|
||||
}, []);
|
||||
|
||||
const hasRole = useCallback((requiredRole: UserRole): boolean => {
|
||||
if (!user?.roleName) return false;
|
||||
|
||||
// 管理员拥有所有权限
|
||||
if (user.roleName === UserRole.Administrator) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 特定角色检查
|
||||
return user.roleName === requiredRole;
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
refreshUser();
|
||||
}, [refreshUser]);
|
||||
|
||||
const contextValue = {
|
||||
user,
|
||||
loading,
|
||||
authenticated: !!user,
|
||||
authError,
|
||||
logout,
|
||||
refreshUser,
|
||||
hasRole
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAuth = () => useContext(AuthContext);
|
||||
|
||||
export default AuthContext;
|
||||
@@ -57,3 +57,30 @@ export {
|
||||
restoreConfigs
|
||||
} from './configApi';
|
||||
|
||||
// 导出UserManagement API
|
||||
export {
|
||||
getUsers,
|
||||
getUserById,
|
||||
createUser,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
batchDeleteUsers
|
||||
} from './userManagementApi';
|
||||
|
||||
// 导出PictureManagement API
|
||||
export {
|
||||
getManagementPictures,
|
||||
getManagementPictureById,
|
||||
deleteManagementPicture,
|
||||
batchDeleteManagementPictures,
|
||||
getManagementPicturesByUserId
|
||||
} from './pictureManagementApi';
|
||||
|
||||
// 导出向量数据库 API
|
||||
export {
|
||||
getCurrentVectorDb,
|
||||
switchVectorDb,
|
||||
clearVectors,
|
||||
rebuildVectors
|
||||
} from './vectorDbApi';
|
||||
|
||||
|
||||
58
Web/src/api/pictureManagementApi.ts
Normal file
58
Web/src/api/pictureManagementApi.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { fetchApi } from './fetchClient';
|
||||
import {
|
||||
type BaseResult,
|
||||
type PaginatedResult,
|
||||
type PictureResponse,
|
||||
type BatchDeleteResult
|
||||
} from './types';
|
||||
|
||||
// 获取图片列表
|
||||
export const getManagementPictures = async (
|
||||
page: number = 1,
|
||||
pageSize: number = 10
|
||||
): Promise<PaginatedResult<PictureResponse>> => {
|
||||
const response = await fetchApi(`/management/picture/get_pictures?page=${page}&pageSize=${pageSize}`);
|
||||
return response as PaginatedResult<PictureResponse>;
|
||||
};
|
||||
|
||||
// 根据ID获取单张图片
|
||||
export const getManagementPictureById = async (id: number): Promise<BaseResult<PictureResponse>> => {
|
||||
return fetchApi<PictureResponse>(
|
||||
`/management/picture/get_picture/${id}`,
|
||||
{ method: 'GET' }
|
||||
);
|
||||
};
|
||||
|
||||
// 删除图片
|
||||
export const deleteManagementPicture = async (id: number): Promise<BaseResult<boolean>> => {
|
||||
return fetchApi<boolean>(
|
||||
'/management/picture/delete_picture',
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(id)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// 批量删除图片
|
||||
export const batchDeleteManagementPictures = async (
|
||||
ids: number[]
|
||||
): Promise<BaseResult<BatchDeleteResult>> => {
|
||||
return fetchApi<BatchDeleteResult>(
|
||||
'/management/picture/batch_delete_pictures',
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(ids)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// 根据用户ID获取图片
|
||||
export const getManagementPicturesByUserId = async (
|
||||
userId: number,
|
||||
page: number = 1,
|
||||
pageSize: number = 10
|
||||
): Promise<PaginatedResult<PictureResponse>> => {
|
||||
const response = await fetchApi(`/management/picture/get_pictures_by_user/${userId}?page=${page}&pageSize=${pageSize}`);
|
||||
return response as PaginatedResult<PictureResponse>;
|
||||
};
|
||||
@@ -227,3 +227,47 @@ export interface UpdatePictureRequest {
|
||||
description?: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
// 用户管理相关类型
|
||||
export interface UserResponse {
|
||||
id: number;
|
||||
userName: string;
|
||||
email: string;
|
||||
role: string;
|
||||
createdAt: Date;
|
||||
lastLoginAt?: Date;
|
||||
}
|
||||
|
||||
// 管理员创建用户请求
|
||||
export interface CreateUserRequest {
|
||||
userName: string;
|
||||
email: string;
|
||||
password: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
// 管理员更新用户请求
|
||||
export interface AdminUpdateUserRequest {
|
||||
id: number;
|
||||
userName?: string;
|
||||
email?: string;
|
||||
role?: string;
|
||||
}
|
||||
|
||||
// 批量删除结果
|
||||
export interface BatchDeleteResult {
|
||||
successCount: number;
|
||||
failedCount: number;
|
||||
failedIds?: number[];
|
||||
}
|
||||
|
||||
export type VectorDbType = "InMemory" | "Qdrant";
|
||||
|
||||
export const VectorDbType = {
|
||||
InMemory: "InMemory" as VectorDbType,
|
||||
Qdrant: "Qdrant" as VectorDbType,
|
||||
};
|
||||
|
||||
export interface VectorDbInfo {
|
||||
type: string;
|
||||
}
|
||||
|
||||
76
Web/src/api/userManagementApi.ts
Normal file
76
Web/src/api/userManagementApi.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { fetchApi } from './fetchClient';
|
||||
import {
|
||||
type BaseResult,
|
||||
type PaginatedResult,
|
||||
type UserResponse,
|
||||
type CreateUserRequest,
|
||||
type AdminUpdateUserRequest,
|
||||
type BatchDeleteResult
|
||||
} from './types';
|
||||
|
||||
// 获取用户列表
|
||||
export const getUsers = async (
|
||||
page: number = 1,
|
||||
pageSize: number = 10
|
||||
): Promise<PaginatedResult<UserResponse>> => {
|
||||
const response = await fetchApi(`/management/user/get_users?page=${page}&pageSize=${pageSize}`);
|
||||
return response as PaginatedResult<UserResponse>;
|
||||
};
|
||||
|
||||
// 根据ID获取单个用户
|
||||
export const getUserById = async (id: number): Promise<BaseResult<UserResponse>> => {
|
||||
return fetchApi<UserResponse>(
|
||||
`/management/user/get_user/${id}`,
|
||||
{ method: 'GET' }
|
||||
);
|
||||
};
|
||||
|
||||
// 创建用户
|
||||
export const createUser = async (
|
||||
userData: CreateUserRequest
|
||||
): Promise<BaseResult<UserResponse>> => {
|
||||
return fetchApi<UserResponse>(
|
||||
'/management/user/create_user',
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(userData)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// 更新用户
|
||||
export const updateUser = async (
|
||||
userData: AdminUpdateUserRequest
|
||||
): Promise<BaseResult<UserResponse>> => {
|
||||
return fetchApi<UserResponse>(
|
||||
'/management/user/update_user',
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(userData)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// 删除用户
|
||||
export const deleteUser = async (id: number): Promise<BaseResult<boolean>> => {
|
||||
return fetchApi<boolean>(
|
||||
'/management/user/delete_user',
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(id)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// 批量删除用户
|
||||
export const batchDeleteUsers = async (
|
||||
ids: number[]
|
||||
): Promise<BaseResult<BatchDeleteResult>> => {
|
||||
return fetchApi<BatchDeleteResult>(
|
||||
'/management/user/batch_delete_users',
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(ids)
|
||||
}
|
||||
);
|
||||
};
|
||||
61
Web/src/api/vectorDbApi.ts
Normal file
61
Web/src/api/vectorDbApi.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { type BaseResult, type VectorDbInfo, VectorDbType } from './types';
|
||||
import { fetchApi } from './fetchClient';
|
||||
|
||||
// 获取当前向量数据库类型
|
||||
export const getCurrentVectorDb = async (): Promise<BaseResult<VectorDbInfo>> => {
|
||||
try {
|
||||
return await fetchApi<VectorDbInfo>('/management/system/vector-db/current');
|
||||
} catch (error: any) {
|
||||
return {
|
||||
success: false,
|
||||
message: `获取当前向量数据库失败: ${error.message}`,
|
||||
code: 500
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 切换向量数据库类型
|
||||
export const switchVectorDb = async (type: VectorDbType): Promise<BaseResult<boolean>> => {
|
||||
try {
|
||||
return await fetchApi<boolean>('/management/system/vector-db/switch', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ type }),
|
||||
});
|
||||
} catch (error: any) {
|
||||
return {
|
||||
success: false,
|
||||
message: `切换向量数据库失败: ${error.message}`,
|
||||
code: 500
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 清空向量数据库
|
||||
export const clearVectors = async (): Promise<BaseResult<boolean>> => {
|
||||
try {
|
||||
return await fetchApi<boolean>('/management/system/vector-db/clear', {
|
||||
method: 'DELETE'
|
||||
});
|
||||
} catch (error: any) {
|
||||
return {
|
||||
success: false,
|
||||
message: `清空向量数据库失败: ${error.message}`,
|
||||
code: 500
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 重建向量数据库
|
||||
export const rebuildVectors = async (): Promise<BaseResult<boolean>> => {
|
||||
try {
|
||||
return await fetchApi<boolean>('/management/system/vector-db/rebuild', {
|
||||
method: 'POST'
|
||||
});
|
||||
} catch (error: any) {
|
||||
return {
|
||||
success: false,
|
||||
message: `重建向量数据库失败: ${error.message}`,
|
||||
code: 500
|
||||
};
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user