feat: Support multiple vector database selection, add InMemory and Qdrant adapters, introduce admin dashboard

This commit is contained in:
shiyu
2025-05-31 21:00:48 +08:00
parent b2bacc54a9
commit 44d2616fd4
51 changed files with 5498 additions and 1214 deletions

View File

@@ -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;

View File

@@ -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';

View 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>;
};

View File

@@ -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;
}

View 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)
}
);
};

View 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
};
}
};