ソースを参照

Merge remote-tracking branch 'upstream/main'

yourname 7 ヶ月 前
コミット
496b634897

+ 0 - 782
client/admin/api.ts

@@ -1,782 +0,0 @@
-import axios from 'axios';
-import { getGlobalConfig } from './utils.ts';
-import type { MinioUploadPolicy, OSSUploadPolicy } from '@d8d-appcontainer/types';
-import 'dayjs/locale/zh-cn';
-import type { 
-  User, FileLibrary, FileCategory, ThemeSettings,
- SystemSetting, SystemSettingGroupData, 
- LoginLocation, LoginLocationDetail,
- Message, UserMessage, KnowInfo
-} from '../share/types.ts';
-
-
-
-// 定义API基础URL
-const API_BASE_URL = '/api';
-
-// 获取OSS完整URL
-export const getOssUrl = (path: string): string => {
-  // 获取全局配置中的OSS_HOST,如果不存在使用默认值
-  const ossHost = getGlobalConfig('OSS_BASE_URL') || '';
-  // 确保path不以/开头
-  const ossPath = path.startsWith('/') ? path.substring(1) : path;
-  return `${ossHost}/${ossPath}`;
-};
-
-// ===================
-// Auth API 定义部分
-// ===================
-
-// 定义API返回数据类型
-interface AuthLoginResponse {
-  message: string;
-  token: string;
-  refreshToken?: string;
-  user: User;
-}
-
-interface AuthResponse {
-  message: string;
-  [key: string]: any;
-}
-
-// 定义Auth API接口类型
-interface AuthAPIType {
-  login: (username: string, password: string, latitude?: number, longitude?: number) => Promise<AuthLoginResponse>;
-  register: (username: string, email: string, password: string) => Promise<AuthResponse>;
-  logout: () => Promise<AuthResponse>;
-  getCurrentUser: () => Promise<User>;
-  updateUser: (userId: number, userData: Partial<User>) => Promise<User>;
-  changePassword: (oldPassword: string, newPassword: string) => Promise<AuthResponse>;
-  requestPasswordReset: (email: string) => Promise<AuthResponse>;
-  resetPassword: (token: string, newPassword: string) => Promise<AuthResponse>;
-}
-
-
-// Auth相关API
-export const AuthAPI: AuthAPIType = {
-  // 登录API
-  login: async (username: string, password: string, latitude?: number, longitude?: number) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/login`, {
-        username,
-        password,
-        latitude,
-        longitude
-      });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 注册API
-  register: async (username: string, email: string, password: string) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/register`, { username, email, password });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 登出API
-  logout: async () => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/logout`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 获取当前用户信息
-  getCurrentUser: async () => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/auth/me`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 更新用户信息
-  updateUser: async (userId: number, userData: Partial<User>) => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/auth/users/${userId}`, userData);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 修改密码
-  changePassword: async (oldPassword: string, newPassword: string) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/change-password`, { oldPassword, newPassword });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 请求重置密码
-  requestPasswordReset: async (email: string) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/request-password-reset`, { email });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 重置密码
-  resetPassword: async (token: string, newPassword: string) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/reset-password`, { token, newPassword });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 为UserAPI添加的接口响应类型
-interface UsersResponse {
-  data: User[];
-  pagination: {
-    total: number;
-    current: number;
-    pageSize: number;
-    totalPages: number;
-  };
-}
-
-interface UserResponse {
-  data: User;
-  message?: string;
-}
-
-interface UserCreateResponse {
-  message: string;
-  data: User;
-}
-
-interface UserUpdateResponse {
-  message: string;
-  data: User;
-}
-
-interface UserDeleteResponse {
-  message: string;
-  id: number;
-}
-
-// 用户管理API
-export const UserAPI = {
-  // 获取用户列表
-  getUsers: async (params?: { page?: number, limit?: number, search?: string }): Promise<UsersResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/users`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 获取单个用户详情
-  getUser: async (userId: number): Promise<UserResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/users/${userId}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 创建用户
-  createUser: async (userData: Partial<User>): Promise<UserCreateResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/users`, userData);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 更新用户信息
-  updateUser: async (userId: number, userData: Partial<User>): Promise<UserUpdateResponse> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/users/${userId}`, userData);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 删除用户
-  deleteUser: async (userId: number): Promise<UserDeleteResponse> => {
-    try {
-      const response = await axios.delete(`${API_BASE_URL}/users/${userId}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-
-// 定义文件相关接口类型
-interface FileUploadPolicyResponse {
-  message: string;
-  data: MinioUploadPolicy | OSSUploadPolicy;
-}
-
-interface FileListResponse {
-  message: string;
-  data: {
-    list: FileLibrary[];
-    pagination: {
-      current: number;
-      pageSize: number;
-      total: number;
-    };
-  };
-}
-
-interface FileSaveResponse {
-  message: string;
-  data: FileLibrary;
-}
-
-interface FileInfoResponse {
-  message: string;
-  data: FileLibrary;
-}
-
-interface FileDeleteResponse {
-  message: string;
-}
-
-
-interface FileCategoryListResponse {
-  data: FileCategory[];
-  total: number;
-  page: number;
-  pageSize: number;
-}
-
-interface FileCategoryCreateResponse {
-  message: string;
-  data: FileCategory;
-}
-
-interface FileCategoryUpdateResponse {
-  message: string;
-  data: FileCategory;
-}
-
-interface FileCategoryDeleteResponse {
-  message: string;
-}
-
-// 文件API接口定义
-export const FileAPI = {
-  // 获取文件上传策略
-  getUploadPolicy: async (filename: string, prefix: string = 'uploads/', maxSize: number = 10 * 1024 * 1024): Promise<FileUploadPolicyResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/upload/policy`, { 
-        params: { filename, prefix, maxSize } 
-      });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 保存文件信息
-  saveFileInfo: async (fileData: Partial<FileLibrary>): Promise<FileSaveResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/upload/save`, fileData);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取文件列表
-  getFileList: async (params?: {
-    page?: number,
-    pageSize?: number,
-    category_id?: number,
-    fileType?: string,
-    keyword?: string
-  }): Promise<FileListResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/upload/list`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取单个文件信息
-  getFileInfo: async (id: number): Promise<FileInfoResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/upload/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新文件下载计数
-  updateDownloadCount: async (id: number): Promise<FileDeleteResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/upload/${id}/download`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 删除文件
-  deleteFile: async (id: number): Promise<FileDeleteResponse> => {
-    try {
-      const response = await axios.delete(`${API_BASE_URL}/upload/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取文件分类列表
-  getCategories: async (params?: {
-    page?: number,
-    pageSize?: number,
-    search?: string
-  }): Promise<FileCategoryListResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/file-categories`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 创建文件分类
-  createCategory: async (data: Partial<FileCategory>): Promise<FileCategoryCreateResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/file-categories`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新文件分类
-  updateCategory: async (id: number, data: Partial<FileCategory>): Promise<FileCategoryUpdateResponse> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/file-categories/${id}`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 删除文件分类
-  deleteCategory: async (id: number): Promise<FileCategoryDeleteResponse> => {
-    try {
-      const response = await axios.delete(`${API_BASE_URL}/file-categories/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// Theme API 响应类型
-export interface ThemeSettingsResponse {
-  message: string;
-  data: ThemeSettings;
-}
-
-// Theme API 定义
-export const ThemeAPI = {
-  // 获取主题设置
-  getThemeSettings: async (): Promise<ThemeSettings> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/theme`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新主题设置
-  updateThemeSettings: async (themeData: Partial<ThemeSettings>): Promise<ThemeSettings> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/theme`, themeData);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 重置主题设置
-  resetThemeSettings: async (): Promise<ThemeSettings> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/theme/reset`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 图表数据API接口类型
-interface ChartDataResponse<T> {
-  message: string;
-  data: T;
-}
-
-interface UserActivityData {
-  date: string;
-  count: number;
-}
-
-interface FileUploadsData {
-  month: string;
-  count: number;
-}
-
-interface FileTypesData {
-  type: string;
-  value: number;
-}
-
-interface DashboardOverviewData {
-  userCount: number;
-  fileCount: number;
-  articleCount: number;
-  todayLoginCount: number;
-}
-
-// 图表数据API
-export const ChartAPI = {
-  // 获取用户活跃度数据
-  getUserActivity: async (): Promise<ChartDataResponse<UserActivityData[]>> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/charts/user-activity`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取文件上传统计数据
-  getFileUploads: async (): Promise<ChartDataResponse<FileUploadsData[]>> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/charts/file-uploads`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取文件类型分布数据
-  getFileTypes: async (): Promise<ChartDataResponse<FileTypesData[]>> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/charts/file-types`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取仪表盘概览数据
-  getDashboardOverview: async (): Promise<ChartDataResponse<DashboardOverviewData>> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/charts/dashboard-overview`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 消息API接口类型
-interface MessagesResponse {
-  data: UserMessage[];
-  pagination: {
-    total: number;
-    current: number;
-    pageSize: number;
-    totalPages: number;
-  };
-}
-
-interface MessageResponse {
-  data: Message;
-  message?: string;
-}
-
-interface MessageCountResponse {
-  count: number;
-}
-
-// 消息API
-export const MessageAPI = {
-  // 获取消息列表
-  getMessages: async (params?: {
-    page?: number,
-    pageSize?: number,
-    type?: string,
-    status?: string,
-    search?: string
-  }): Promise<MessagesResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/messages`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 发送消息
-  sendMessage: async (data: {
-    title: string,
-    content: string,
-    type: string,
-    receiver_ids: number[]
-  }): Promise<MessageResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/messages`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取未读消息数
-  getUnreadCount: async (): Promise<MessageCountResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/messages/count/unread`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 标记消息为已读
-  markAsRead: async (id: number): Promise<MessageResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/messages/${id}/read`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 删除消息
-  deleteMessage: async (id: number): Promise<MessageResponse> => {
-    try {
-      const response = await axios.delete(`${API_BASE_URL}/messages/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 地图相关API的接口类型定义
-export interface LoginLocationResponse {
-  message: string;
-  data: LoginLocation[];
-}
-
-export interface LoginLocationDetailResponse {
-  message: string;
-  data: LoginLocationDetail;
-}
-
-export interface LoginLocationUpdateResponse {
-  message: string;
-  data: LoginLocationDetail;
-}
-
-// 知识库相关接口类型定义
-export interface KnowInfoListResponse {
-  data: KnowInfo[];
-  pagination: {
-    total: number;
-    current: number;
-    pageSize: number;
-    totalPages: number;
-  };
-}
-
-interface KnowInfoResponse {
-  data: KnowInfo;
-  message?: string;
-}
-
-interface KnowInfoCreateResponse {
-  message: string;
-  data: KnowInfo;
-}
-
-interface KnowInfoUpdateResponse {
-  message: string;
-  data: KnowInfo;
-}
-
-interface KnowInfoDeleteResponse {
-  message: string;
-  id: number;
-}
-
-
-// 地图相关API
-export const MapAPI = {
-  // 获取地图标记点数据
-  getMarkers: async (params?: { 
-    startTime?: string; 
-    endTime?: string; 
-    userId?: number 
-  }): Promise<LoginLocationResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/map/markers`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取登录位置详情
-  getLocationDetail: async (locationId: number): Promise<LoginLocationDetailResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/map/location/${locationId}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新登录位置信息
-  updateLocation: async (locationId: number, data: { 
-    longitude: number; 
-    latitude: number; 
-    location_name?: string; 
-  }): Promise<LoginLocationUpdateResponse> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/map/location/${locationId}`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 系统设置API
-// 知识库API
-export const KnowInfoAPI = {
-  // 获取知识库列表
-  getKnowInfos: async (params?: {
-    page?: number;
-    pageSize?: number;
-    title?: string;
-    category?: string;
-    tags?: string;
-  }): Promise<KnowInfoListResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/know-infos`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取单个知识详情
-  getKnowInfo: async (id: number): Promise<KnowInfoResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/know-infos/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 创建知识
-  createKnowInfo: async (data: Partial<KnowInfo>): Promise<KnowInfoCreateResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/know-infos`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新知识
-  updateKnowInfo: async (id: number, data: Partial<KnowInfo>): Promise<KnowInfoUpdateResponse> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/know-infos/${id}`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 删除知识
-  deleteKnowInfo: async (id: number): Promise<KnowInfoDeleteResponse> => {
-    try {
-      const response = await axios.delete(`${API_BASE_URL}/know-infos/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-export const SystemAPI = {
-  // 获取所有系统设置
-  getSettings: async (): Promise<SystemSettingGroupData[]> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/settings`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取指定分组的系统设置
-  getSettingsByGroup: async (group: string): Promise<SystemSetting[]> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/settings/group/${group}`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新系统设置
-  updateSettings: async (settings: Partial<SystemSetting>[]): Promise<SystemSetting[]> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/settings`, settings);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 重置系统设置
-  resetSettings: async (): Promise<SystemSetting[]> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/settings/reset`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-

+ 104 - 0
client/admin/api/auth.ts

@@ -0,0 +1,104 @@
+import axios from 'axios';
+import type { User } from '../../share/types.ts';
+
+interface AuthLoginResponse {
+  message: string;
+  token: string;
+  refreshToken?: string;
+  user: User;
+}
+
+interface AuthResponse {
+  message: string;
+  [key: string]: any;
+}
+
+interface AuthAPIType {
+  login: (username: string, password: string, latitude?: number, longitude?: number) => Promise<AuthLoginResponse>;
+  register: (username: string, email: string, password: string) => Promise<AuthResponse>;
+  logout: () => Promise<AuthResponse>;
+  getCurrentUser: () => Promise<User>;
+  updateUser: (userId: number, userData: Partial<User>) => Promise<User>;
+  changePassword: (oldPassword: string, newPassword: string) => Promise<AuthResponse>;
+  requestPasswordReset: (email: string) => Promise<AuthResponse>;
+  resetPassword: (token: string, newPassword: string) => Promise<AuthResponse>;
+}
+
+export const AuthAPI: AuthAPIType = {
+  login: async (username: string, password: string, latitude?: number, longitude?: number) => {
+    try {
+      const response = await axios.post('/auth/login', {
+        username,
+        password,
+        latitude,
+        longitude
+      });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  register: async (username: string, email: string, password: string) => {
+    try {
+      const response = await axios.post('/auth/register', { username, email, password });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  logout: async () => {
+    try {
+      const response = await axios.post('/auth/logout');
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  getCurrentUser: async () => {
+    try {
+      const response = await axios.get('/auth/me');
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  updateUser: async (userId: number, userData: Partial<User>) => {
+    try {
+      const response = await axios.put(`/auth/users/${userId}`, userData);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  changePassword: async (oldPassword: string, newPassword: string) => {
+    try {
+      const response = await axios.post('/auth/change-password', { oldPassword, newPassword });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  requestPasswordReset: async (email: string) => {
+    try {
+      const response = await axios.post('/auth/request-password-reset', { email });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  resetPassword: async (token: string, newPassword: string) => {
+    try {
+      const response = await axios.post('/auth/reset-password', { token, newPassword });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};

+ 66 - 0
client/admin/api/charts.ts

@@ -0,0 +1,66 @@
+import axios from 'axios';
+
+interface ChartDataResponse<T> {
+  message: string;
+  data: T;
+}
+
+interface UserActivityData {
+  date: string;
+  count: number;
+}
+
+interface FileUploadsData {
+  month: string;
+  count: number;
+}
+
+interface FileTypesData {
+  type: string;
+  value: number;
+}
+
+interface DashboardOverviewData {
+  userCount: number;
+  fileCount: number;
+  articleCount: number;
+  todayLoginCount: number;
+}
+
+export const ChartAPI = {
+  getUserActivity: async (): Promise<ChartDataResponse<UserActivityData[]>> => {
+    try {
+      const response = await axios.get('/charts/user-activity');
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  getFileUploads: async (): Promise<ChartDataResponse<FileUploadsData[]>> => {
+    try {
+      const response = await axios.get('/charts/file-uploads');
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  getFileTypes: async (): Promise<ChartDataResponse<FileTypesData[]>> => {
+    try {
+      const response = await axios.get('/charts/file-types');
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  getDashboardOverview: async (): Promise<ChartDataResponse<DashboardOverviewData>> => {
+    try {
+      const response = await axios.get('/charts/dashboard-overview');
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};

+ 159 - 0
client/admin/api/files.ts

@@ -0,0 +1,159 @@
+import axios from 'axios';
+import type { FileLibrary, FileCategory } from '../../share/types.ts';
+import type { MinioUploadPolicy, OSSUploadPolicy } from '@d8d-appcontainer/types';
+
+interface FileUploadPolicyResponse {
+  message: string;
+  data: MinioUploadPolicy | OSSUploadPolicy;
+}
+
+interface FileListResponse {
+  message: string;
+  data: {
+    list: FileLibrary[];
+    pagination: {
+      current: number;
+      pageSize: number;
+      total: number;
+    };
+  };
+}
+
+interface FileSaveResponse {
+  message: string;
+  data: FileLibrary;
+}
+
+interface FileInfoResponse {
+  message: string;
+  data: FileLibrary;
+}
+
+interface FileDeleteResponse {
+  message: string;
+}
+
+interface FileCategoryListResponse {
+  data: FileCategory[];
+  total: number;
+  page: number;
+  pageSize: number;
+}
+
+interface FileCategoryCreateResponse {
+  message: string;
+  data: FileCategory;
+}
+
+interface FileCategoryUpdateResponse {
+  message: string;
+  data: FileCategory;
+}
+
+interface FileCategoryDeleteResponse {
+  message: string;
+}
+
+export const FileAPI = {
+  getUploadPolicy: async (filename: string, prefix: string = 'uploads/', maxSize: number = 10 * 1024 * 1024): Promise<FileUploadPolicyResponse> => {
+    try {
+      const response = await axios.get('/upload/policy', {
+        params: { filename, prefix, maxSize } 
+      });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  saveFileInfo: async (fileData: Partial<FileLibrary>): Promise<FileSaveResponse> => {
+    try {
+      const response = await axios.post('/upload/save', fileData);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  getFileList: async (params?: {
+    page?: number,
+    pageSize?: number,
+    category_id?: number,
+    fileType?: string,
+    keyword?: string
+  }): Promise<FileListResponse> => {
+    try {
+      const response = await axios.get('/upload/list', { params });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  getFileInfo: async (id: number): Promise<FileInfoResponse> => {
+    try {
+      const response = await axios.get(`/upload/${id}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  updateDownloadCount: async (id: number): Promise<FileDeleteResponse> => {
+    try {
+      const response = await axios.post(`/upload/${id}/download`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  deleteFile: async (id: number): Promise<FileDeleteResponse> => {
+    try {
+      const response = await axios.delete(`/upload/${id}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  getCategories: async (params?: {
+    page?: number,
+    pageSize?: number,
+    search?: string
+  }): Promise<FileCategoryListResponse> => {
+    try {
+      const response = await axios.get('/file-categories', { params });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  createCategory: async (data: Partial<FileCategory>): Promise<FileCategoryCreateResponse> => {
+    try {
+      const response = await axios.post('/file-categories', data);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  updateCategory: async (id: number, data: Partial<FileCategory>): Promise<FileCategoryUpdateResponse> => {
+    try {
+      const response = await axios.put(`/file-categories/${id}`, data);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  deleteCategory: async (id: number): Promise<FileCategoryDeleteResponse> => {
+    try {
+      const response = await axios.delete(`/file-categories/${id}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};

+ 25 - 0
client/admin/api/index.ts

@@ -0,0 +1,25 @@
+import axios from 'axios';
+
+// 基础配置
+export const API_BASE_URL = '/api';
+// 全局axios配置
+axios.defaults.baseURL = API_BASE_URL;
+
+// 获取OSS完整URL
+export const getOssUrl = (path: string): string => {
+  // 获取全局配置中的OSS_HOST,如果不存在使用默认值
+  const ossHost = (window.CONFIG?.OSS_BASE_URL) || '';
+  // 确保path不以/开头
+  const ossPath = path.startsWith('/') ? path.substring(1) : path;
+  return `${ossHost}/${ossPath}`;
+};
+
+export * from './auth.ts';
+export * from './users.ts';
+export * from './files.ts';
+export * from './theme.ts';
+export * from './charts.ts';
+export * from './messages.ts';
+export * from './sys.ts';
+export * from './know_info.ts';
+export * from './maps.ts';

+ 92 - 0
client/admin/api/know_info.ts

@@ -0,0 +1,92 @@
+import axios from 'axios';
+import type { KnowInfo } from '../../share/types.ts';
+
+export interface KnowInfoListResponse {
+  data: KnowInfo[];
+  pagination: {
+    current: number;
+    pageSize: number;
+    total: number;
+    totalPages: number;
+  };
+}
+
+interface KnowInfoResponse {
+  data: KnowInfo;
+  message?: string;
+}
+
+interface KnowInfoCreateResponse {
+  message: string;
+  data: KnowInfo;
+}
+
+interface KnowInfoUpdateResponse {
+  message: string;
+  data: KnowInfo;
+}
+
+interface KnowInfoDeleteResponse {
+  message: string;
+  id: number;
+}
+
+
+// 知识库API
+export const KnowInfoAPI = {
+  // 获取知识库列表
+  getKnowInfos: async (params?: {
+    page?: number;
+    pageSize?: number;
+    title?: string;
+    category?: string;
+    tags?: string;
+  }): Promise<KnowInfoListResponse> => {
+    try {
+      const response = await axios.get('/know-infos', { params });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 获取单个知识详情
+  getKnowInfo: async (id: number): Promise<KnowInfoResponse> => {
+    try {
+      const response = await axios.get(`/know-infos/${id}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 创建知识
+  createKnowInfo: async (data: Partial<KnowInfo>): Promise<KnowInfoCreateResponse> => {
+    try {
+      const response = await axios.post('/know-infos', data);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 更新知识
+  updateKnowInfo: async (id: number, data: Partial<KnowInfo>): Promise<KnowInfoUpdateResponse> => {
+    try {
+      const response = await axios.put(`/know-infos/${id}`, data);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 删除知识
+  deleteKnowInfo: async (id: number): Promise<KnowInfoDeleteResponse> => {
+    try {
+      const response = await axios.delete(`/know-infos/${id}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};

+ 63 - 0
client/admin/api/maps.ts

@@ -0,0 +1,63 @@
+import axios from 'axios';
+import { API_BASE_URL } from './index.ts';
+import type {
+ LoginLocation, LoginLocationDetail,
+} from '../../share/types.ts';
+
+
+// 地图相关API的接口类型定义
+export interface LoginLocationResponse {
+  message: string;
+  data: LoginLocation[];
+}
+
+export interface LoginLocationDetailResponse {
+  message: string;
+  data: LoginLocationDetail;
+}
+
+export interface LoginLocationUpdateResponse {
+  message: string;
+  data: LoginLocationDetail;
+}
+
+// 地图相关API
+export const MapAPI = {
+  // 获取地图标记点数据
+  getMarkers: async (params?: { 
+    startTime?: string; 
+    endTime?: string; 
+    userId?: number 
+  }): Promise<LoginLocationResponse> => {
+    try {
+      const response = await axios.get(`${API_BASE_URL}/map/markers`, { params });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 获取登录位置详情
+  getLocationDetail: async (locationId: number): Promise<LoginLocationDetailResponse> => {
+    try {
+      const response = await axios.get(`${API_BASE_URL}/map/location/${locationId}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 更新登录位置信息
+  updateLocation: async (locationId: number, data: { 
+    longitude: number; 
+    latitude: number; 
+    location_name?: string; 
+  }): Promise<LoginLocationUpdateResponse> => {
+    try {
+      const response = await axios.put(`${API_BASE_URL}/map/location/${locationId}`, data);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};

+ 79 - 0
client/admin/api/messages.ts

@@ -0,0 +1,79 @@
+import axios from 'axios';
+import type { UserMessage, Message } from '../../share/types.ts';
+
+interface MessagesResponse {
+  data: UserMessage[];
+  pagination: {
+    total: number;
+    current: number;
+    pageSize: number;
+    totalPages: number;
+  };
+}
+
+interface MessageResponse {
+  data: Message;
+  message?: string;
+}
+
+interface MessageCountResponse {
+  count: number;
+}
+
+export const MessageAPI = {
+  getMessages: async (params?: {
+    page?: number,
+    pageSize?: number,
+    type?: string,
+    status?: string,
+    search?: string
+  }): Promise<MessagesResponse> => {
+    try {
+      const response = await axios.get('/messages', { params });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  sendMessage: async (data: {
+    title: string,
+    content: string,
+    type: string,
+    receiver_ids: number[]
+  }): Promise<MessageResponse> => {
+    try {
+      const response = await axios.post('/messages', data);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  getUnreadCount: async (): Promise<MessageCountResponse> => {
+    try {
+      const response = await axios.get('/messages/count/unread');
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  markAsRead: async (id: number): Promise<MessageResponse> => {
+    try {
+      const response = await axios.post(`/messages/${id}/read`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  deleteMessage: async (id: number): Promise<MessageResponse> => {
+    try {
+      const response = await axios.delete(`/messages/${id}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};

+ 47 - 0
client/admin/api/sys.ts

@@ -0,0 +1,47 @@
+import axios from 'axios';
+
+import type {
+ SystemSetting, SystemSettingGroupData,
+} from '../../share/types.ts';
+
+export const SystemAPI = {
+  // 获取所有系统设置
+  getSettings: async (): Promise<SystemSettingGroupData[]> => {
+    try {
+      const response = await axios.get('/settings');
+      return response.data.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 获取指定分组的系统设置
+  getSettingsByGroup: async (group: string): Promise<SystemSetting[]> => {
+    try {
+      const response = await axios.get(`/settings/group/${group}`);
+      return response.data.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 更新系统设置
+  updateSettings: async (settings: Partial<SystemSetting>[]): Promise<SystemSetting[]> => {
+    try {
+      const response = await axios.put('/settings', settings);
+      return response.data.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 重置系统设置
+  resetSettings: async (): Promise<SystemSetting[]> => {
+    try {
+      const response = await axios.post('/settings/reset');
+      return response.data.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};

+ 36 - 0
client/admin/api/theme.ts

@@ -0,0 +1,36 @@
+import axios from 'axios';
+import type { ThemeSettings } from '../../share/types.ts';
+
+export interface ThemeSettingsResponse {
+  message: string;
+  data: ThemeSettings;
+}
+
+export const ThemeAPI = {
+  getThemeSettings: async (): Promise<ThemeSettings> => {
+    try {
+      const response = await axios.get('/theme');
+      return response.data.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  updateThemeSettings: async (themeData: Partial<ThemeSettings>): Promise<ThemeSettings> => {
+    try {
+      const response = await axios.put('/theme', themeData);
+      return response.data.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  resetThemeSettings: async (): Promise<ThemeSettings> => {
+    try {
+      const response = await axios.post('/theme/reset');
+      return response.data.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};

+ 79 - 0
client/admin/api/users.ts

@@ -0,0 +1,79 @@
+import axios from 'axios';
+import type { User } from '../../share/types.ts';
+
+interface UsersResponse {
+  data: User[];
+  pagination: {
+    total: number;
+    current: number;
+    pageSize: number;
+    totalPages: number;
+  };
+}
+
+interface UserResponse {
+  data: User;
+  message?: string;
+}
+
+interface UserCreateResponse {
+  message: string;
+  data: User;
+}
+
+interface UserUpdateResponse {
+  message: string;
+  data: User;
+}
+
+interface UserDeleteResponse {
+  message: string;
+  id: number;
+}
+
+export const UserAPI = {
+  getUsers: async (params?: { page?: number, limit?: number, search?: string }): Promise<UsersResponse> => {
+    try {
+      const response = await axios.get('/users', { params });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  getUser: async (userId: number): Promise<UserResponse> => {
+    try {
+      const response = await axios.get(`/users/${userId}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  createUser: async (userData: Partial<User>): Promise<UserCreateResponse> => {
+    try {
+      const response = await axios.post('/users', userData);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  updateUser: async (userId: number, userData: Partial<User>): Promise<UserUpdateResponse> => {
+    try {
+      const response = await axios.put(`/users/${userId}`, userData);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+  
+  deleteUser: async (userId: number): Promise<UserDeleteResponse> => {
+    try {
+      const response = await axios.delete(`/users/${userId}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};

+ 1 - 1
client/admin/components_uploader.tsx

@@ -16,7 +16,7 @@ import type { MinioUploadPolicy, OSSUploadPolicy } from '@d8d-appcontainer/types
 import 'dayjs/locale/zh-cn';
 import { OssType } from '../share/types.ts';
 
-import { FileAPI } from './api.ts';
+import { FileAPI } from './api/index.ts';
 
 // MinIO文件上传组件
 export const Uploader = ({ 

+ 1 - 1
client/admin/hooks_sys.tsx

@@ -24,7 +24,7 @@ import {
 import {
   AuthAPI,
   ThemeAPI
-} from './api.ts';
+} from './api/index.ts';
 
 
 // 配置 dayjs 插件

+ 10 - 18
client/admin/pages_chart.tsx

@@ -1,11 +1,6 @@
 import React from 'react';
 import { 
-  Layout, Menu, Button, Table, Space,
-  Form, Input, Select, message, Modal,
-  Card, Spin, Row, Col, Breadcrumb, Avatar,
-  Dropdown, ConfigProvider, theme, Typography,
-  Switch, Badge, Image, Upload, Divider, Descriptions,
-  Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer
+  Card, Spin, Row, Col, Statistic,
 } from 'antd';
 
 import { 
@@ -15,13 +10,10 @@ import { Line , Pie, Column} from "@ant-design/plots";
 import 'dayjs/locale/zh-cn';
 
 
-import { ChartAPI } from './api.ts';
+import { ChartAPI } from './api/index.ts';
 import { useTheme } from './hooks_sys.tsx';
 
-interface ChartTooltipInfo {
-  items: Array<Record<string, any>>;
-  title: string;
-}
+
 
 // 用户活跃度图表组件
 const UserActivityChart: React.FC = () => {
@@ -49,7 +41,7 @@ const UserActivityChart: React.FC = () => {
   };
 
   return (
-    <Card title="用户活跃度趋势" bordered={false}>
+    <Card title="用户活跃度趋势" variant="borderless">
       <Line {...config} />
     </Card>
   );
@@ -92,7 +84,7 @@ const FileUploadsChart: React.FC = () => {
   };
 
   return (
-    <Card title="文件上传统计" bordered={false}>
+    <Card title="文件上传统计" variant="borderless">
       <Column {...config} />
     </Card>
   );
@@ -130,7 +122,7 @@ const FileTypesChart: React.FC = () => {
   };
 
   return (
-    <Card title="文件类型分布" bordered={false}>
+    <Card title="文件类型分布" variant="borderless">
       <Pie {...config} />
     </Card>
   );
@@ -151,7 +143,7 @@ const DashboardOverview: React.FC = () => {
   return (
     <Row gutter={[16, 16]}>
       <Col xs={12} sm={12} md={6}>
-        <Card bordered={false}>
+        <Card variant="borderless">
           <Statistic
             title="用户总数"
             value={overviewData?.userCount || 0}
@@ -160,7 +152,7 @@ const DashboardOverview: React.FC = () => {
         </Card>
       </Col>
       <Col xs={12} sm={12} md={6}>
-        <Card bordered={false}>
+        <Card variant="borderless">
           <Statistic
             title="文件总数"
             value={overviewData?.fileCount || 0}
@@ -169,7 +161,7 @@ const DashboardOverview: React.FC = () => {
         </Card>
       </Col>
       <Col xs={12} sm={12} md={6}>
-        <Card bordered={false}>
+        <Card variant="borderless">
           <Statistic
             title="文章总数"
             value={overviewData?.articleCount || 0}
@@ -178,7 +170,7 @@ const DashboardOverview: React.FC = () => {
         </Card>
       </Col>
       <Col xs={12} sm={12} md={6}>
-        <Card bordered={false}>
+        <Card variant="borderless">
           <Statistic
             title="今日登录"
             value={overviewData?.todayLoginCount || 0}

+ 44 - 0
client/admin/pages_dashboard.tsx

@@ -0,0 +1,44 @@
+import React from 'react';
+import { 
+  Card, Row, Col, Typography, Statistic
+} from 'antd';
+
+const { Title } = Typography;
+
+// 仪表盘页面
+export const DashboardPage = () => {
+  return (
+    <div>
+      <Title level={2}>仪表盘</Title>
+      <Row gutter={16}>
+        <Col span={8}>
+          <Card>
+            <Statistic
+              title="活跃用户"
+              value={112893}
+              loading={false}
+            />
+          </Card>
+        </Col>
+        <Col span={8}>
+          <Card>
+            <Statistic
+              title="系统消息"
+              value={93}
+              loading={false}
+            />
+          </Card>
+        </Col>
+        <Col span={8}>
+          <Card>
+            <Statistic
+              title="在线用户"
+              value={1128}
+              loading={false}
+            />
+          </Card>
+        </Col>
+      </Row>
+    </div>
+  );
+};

+ 9 - 336
client/admin/pages_sys.tsx → client/admin/pages_file_library.tsx

@@ -1,11 +1,8 @@
 import React, { useState, useEffect } from 'react';
 import { 
-  Layout, Menu, Button, Table, Space,
-  Form, Input, Select, message, Modal,
-  Card, Spin, Row, Col, Breadcrumb, Avatar,
-  Dropdown, ConfigProvider, theme, Typography,
-  Switch, Badge, Image, Upload, Divider, Descriptions,
-  Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer
+  Button, Table, Space, Form, Input, Select, 
+  message, Modal, Card, Typography, Tag, Popconfirm,
+  Tabs, Image, Upload, Descriptions
 } from 'antd';
 import {
   UploadOutlined,
@@ -14,341 +11,17 @@ import {
   FileWordOutlined,
   FilePdfOutlined,
   FileOutlined,
-} from '@ant-design/icons';   
-import { 
-  useQuery,
-} from '@tanstack/react-query';
+} from '@ant-design/icons';
+import { useQuery } from '@tanstack/react-query';
 import dayjs from 'dayjs';
-import weekday from 'dayjs/plugin/weekday';
-import localeData from 'dayjs/plugin/localeData';
-import { uploadMinIOWithPolicy,uploadOSSWithPolicy } from '@d8d-appcontainer/api';
+import { uploadMinIOWithPolicy, uploadOSSWithPolicy } from '@d8d-appcontainer/api';
 import type { MinioUploadPolicy, OSSUploadPolicy } from '@d8d-appcontainer/types';
-import 'dayjs/locale/zh-cn';
-import type { 
-  FileLibrary, FileCategory, KnowInfo
-} from '../share/types.ts';
-
-import {
-   AuditStatus,AuditStatusNameMap,
-   OssType,
-} from '../share/types.ts';
-
-import { getEnumOptions } from './utils.ts';
-
-import {
-  FileAPI,
-  UserAPI,
-} from './api.ts';
-
-
-// 配置 dayjs 插件
-dayjs.extend(weekday);
-dayjs.extend(localeData);
-
-// 设置 dayjs 语言
-dayjs.locale('zh-cn');
+import { FileAPI } from './api/index.ts';
+import type { FileLibrary, FileCategory } from '../share/types.ts';
+import { OssType } from '../share/types.ts';
 
 const { Title } = Typography;
 
-
-// 仪表盘页面
-export const DashboardPage = () => {
-  return (
-    <div>
-      <Title level={2}>仪表盘</Title>
-      <Row gutter={16}>
-        <Col span={8}>
-          <Card>
-            <Statistic
-              title="活跃用户"
-              value={112893}
-              loading={false}
-            />
-          </Card>
-        </Col>
-        <Col span={8}>
-          <Card>
-            <Statistic
-              title="系统消息"
-              value={93}
-              loading={false}
-            />
-          </Card>
-        </Col>
-        <Col span={8}>
-          <Card>
-            <Statistic
-              title="在线用户"
-              value={1128}
-              loading={false}
-            />
-          </Card>
-        </Col>
-      </Row>
-    </div>
-  );
-};
-
-// 用户管理页面
-export const UsersPage = () => {
-  const [searchParams, setSearchParams] = useState({
-    page: 1,
-    limit: 10,
-    search: ''
-  });
-  const [modalVisible, setModalVisible] = useState(false);
-  const [modalTitle, setModalTitle] = useState('');
-  const [editingUser, setEditingUser] = useState<any>(null);
-  const [form] = Form.useForm();
-
-  const { data: usersData, isLoading, refetch } = useQuery({
-    queryKey: ['users', searchParams],
-    queryFn: async () => {
-      return await UserAPI.getUsers(searchParams);
-    }
-  });
-
-  const users = usersData?.data || [];
-  const pagination = {
-    current: searchParams.page,
-    pageSize: searchParams.limit,
-    total: usersData?.pagination?.total || 0
-  };
-
-  // 处理搜索
-  const handleSearch = (values: any) => {
-    setSearchParams(prev => ({
-      ...prev,
-      search: values.search || '',
-      page: 1
-    }));
-  };
-
-  // 处理分页变化
-  const handleTableChange = (newPagination: any) => {
-    setSearchParams(prev => ({
-      ...prev,
-      page: newPagination.current,
-      limit: newPagination.pageSize
-    }));
-  };
-
-  // 打开创建用户模态框
-  const showCreateModal = () => {
-    setModalTitle('创建用户');
-    setEditingUser(null);
-    form.resetFields();
-    setModalVisible(true);
-  };
-
-  // 打开编辑用户模态框
-  const showEditModal = (user: any) => {
-    setModalTitle('编辑用户');
-    setEditingUser(user);
-    form.setFieldsValue(user);
-    setModalVisible(true);
-  };
-
-  // 处理模态框确认
-  const handleModalOk = async () => {
-    try {
-      const values = await form.validateFields();
-      
-      if (editingUser) {
-        // 编辑用户
-        await UserAPI.updateUser(editingUser.id, values);
-        message.success('用户更新成功');
-      } else {
-        // 创建用户
-        await UserAPI.createUser(values);
-        message.success('用户创建成功');
-      }
-      
-      setModalVisible(false);
-      form.resetFields();
-      refetch(); // 刷新用户列表
-    } catch (error) {
-      console.error('表单提交失败:', error);
-      message.error('操作失败,请重试');
-    }
-  };
-
-  // 处理删除用户
-  const handleDelete = async (id: number) => {
-    try {
-      await UserAPI.deleteUser(id);
-      message.success('用户删除成功');
-      refetch(); // 刷新用户列表
-    } catch (error) {
-      console.error('删除用户失败:', error);
-      message.error('删除失败,请重试');
-    }
-  };
-  
-  const columns = [
-    {
-      title: '用户名',
-      dataIndex: 'username',
-      key: 'username',
-    },
-    {
-      title: '昵称',
-      dataIndex: 'nickname',
-      key: 'nickname',
-    },
-    {
-      title: '邮箱',
-      dataIndex: 'email',
-      key: 'email',
-    },
-    {
-      title: '角色',
-      dataIndex: 'role',
-      key: 'role',
-      render: (role: string) => (
-        <Tag color={role === 'admin' ? 'red' : 'blue'}>
-          {role === 'admin' ? '管理员' : '普通用户'}
-        </Tag>
-      ),
-    },
-    {
-      title: '创建时间',
-      dataIndex: 'created_at',
-      key: 'created_at',
-      render: (date: string) => dayjs(date).format('YYYY-MM-DD HH:mm:ss'),
-    },
-    {
-      title: '操作',
-      key: 'action',
-      render: (_: any, record: any) => (
-        <Space size="middle">
-          <Button type="link" onClick={() => showEditModal(record)}>
-            编辑
-          </Button>
-          <Popconfirm
-            title="确定要删除此用户吗?"
-            onConfirm={() => handleDelete(record.id)}
-            okText="确定"
-            cancelText="取消"
-          >
-            <Button type="link" danger>
-              删除
-            </Button>
-          </Popconfirm>
-        </Space>
-      ),
-    },
-  ];
-  
-  return (
-    <div>
-      <Title level={2}>用户管理</Title>
-      <Card>
-        <Form layout="inline" onFinish={handleSearch} style={{ marginBottom: 16 }}>
-          <Form.Item name="search" label="搜索">
-            <Input placeholder="用户名/昵称/邮箱" allowClear />
-          </Form.Item>
-          <Form.Item>
-            <Space>
-              <Button type="primary" htmlType="submit">
-                搜索
-              </Button>
-              <Button type="primary" onClick={showCreateModal}>
-                创建用户
-              </Button>
-            </Space>
-          </Form.Item>
-        </Form>
-
-        <Table
-          columns={columns}
-          dataSource={users}
-          loading={isLoading}
-          rowKey="id"
-          pagination={{
-            ...pagination,
-            showSizeChanger: true,
-            showQuickJumper: true,
-            showTotal: (total) => `共 ${total} 条记录`
-          }}
-          onChange={handleTableChange}
-        />
-      </Card>
-
-      {/* 创建/编辑用户模态框 */}
-      <Modal
-        title={modalTitle}
-        open={modalVisible}
-        onOk={handleModalOk}
-        onCancel={() => {
-          setModalVisible(false);
-          form.resetFields();
-        }}
-        width={600}
-      >
-        <Form
-          form={form}
-          layout="vertical"
-        >
-          <Form.Item
-            name="username"
-            label="用户名"
-            rules={[
-              { required: true, message: '请输入用户名' },
-              { min: 3, message: '用户名至少3个字符' }
-            ]}
-          >
-            <Input placeholder="请输入用户名" />
-          </Form.Item>
-
-          <Form.Item
-            name="nickname"
-            label="昵称"
-            rules={[{ required: true, message: '请输入昵称' }]}
-          >
-            <Input placeholder="请输入昵称" />
-          </Form.Item>
-
-          <Form.Item
-            name="email"
-            label="邮箱"
-            rules={[
-              { required: true, message: '请输入邮箱' },
-              { type: 'email', message: '请输入有效的邮箱地址' }
-            ]}
-          >
-            <Input placeholder="请输入邮箱" />
-          </Form.Item>
-
-          {!editingUser && (
-            <Form.Item
-              name="password"
-              label="密码"
-              rules={[
-                { required: true, message: '请输入密码' },
-                { min: 6, message: '密码至少6个字符' }
-              ]}
-            >
-              <Input.Password placeholder="请输入密码" />
-            </Form.Item>
-          )}
-
-          <Form.Item
-            name="role"
-            label="角色"
-            rules={[{ required: true, message: '请选择角色' }]}
-          >
-            <Select placeholder="请选择角色">
-              <Select.Option value="user">普通用户</Select.Option>
-              <Select.Option value="admin">管理员</Select.Option>
-            </Select>
-          </Form.Item>
-        </Form>
-      </Modal>
-    </div>
-  );
-};
-
 // 文件库管理页面
 export const FileLibraryPage = () => {
   const [loading, setLoading] = useState(false);

+ 2 - 6
client/admin/pages_know_info.tsx

@@ -24,22 +24,19 @@ import weekday from 'dayjs/plugin/weekday';
 import localeData from 'dayjs/plugin/localeData';
 import 'dayjs/locale/zh-cn';
 import type { 
-  FileLibrary, FileCategory, KnowInfo
+  KnowInfo
 } from '../share/types.ts';
 
 import {
    AuditStatus,AuditStatusNameMap,
-   OssType,
 } from '../share/types.ts';
 
 import { getEnumOptions } from './utils.ts';
 
 import {
-  FileAPI,
-  UserAPI,
   KnowInfoAPI,
   type KnowInfoListResponse
-} from './api.ts';
+} from './api/index.ts';
 
 
 // 配置 dayjs 插件
@@ -49,7 +46,6 @@ dayjs.extend(localeData);
 // 设置 dayjs 语言
 dayjs.locale('zh-cn');
 
-const { Title } = Typography;
 
 
 // 知识库管理页面组件

+ 6 - 13
client/admin/pages_map.tsx

@@ -1,19 +1,11 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState } from 'react';
 import { 
-  Layout, Menu, Button, Table, Space,
-  Form, Input, Select, message, Modal,
-  Card, Spin, Row, Col, Breadcrumb, Avatar,
-  Dropdown, ConfigProvider, theme, Typography,
-  Switch, Badge, Image, Upload, Divider, Descriptions,
-  Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer,
-  Tree
+  Button, Space, Drawer,
+   Select, message, 
+  Card, Spin, Typography,Descriptions,DatePicker, 
 } from 'antd';
 import {
-  MenuFoldOutlined,
-  MenuUnfoldOutlined,
-  AppstoreOutlined,
   EnvironmentOutlined,
-  SearchOutlined,
   ClockCircleOutlined,
   UserOutlined,
   GlobalOutlined
@@ -28,7 +20,8 @@ import type {
    MarkerData, LoginLocation, LoginLocationDetail, User
 } from '../share/types.ts';
 
-import { MapAPI,UserAPI } from './api.ts';
+import { UserAPI } from './api/index.ts';
+import { MapAPI } from './api/index.ts';
 import dayjs from 'dayjs';
 
 const { RangePicker } = DatePicker;

+ 2 - 4
client/admin/pages_messages.tsx

@@ -1,19 +1,17 @@
 import React, { useState } from 'react';
-import { useQuery, useMutation, useQueryClient, UseMutationResult } from '@tanstack/react-query';
+import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
 import { Button, Table, Space, Modal, Form, Input, Select, message } from 'antd';
 import type { TableProps } from 'antd';
 import dayjs from 'dayjs';
 import 'dayjs/locale/zh-cn';
 
-import { MessageAPI } from './api.ts';
-import { UserAPI } from './api.ts';
+import { MessageAPI , UserAPI } from './api/index.ts';
 import type { UserMessage } from '../share/types.ts';
 import { MessageStatusNameMap , MessageStatus} from '../share/types.ts';
 
 export  const MessagesPage = () => {
   const queryClient = useQueryClient();
   const [form] = Form.useForm();
-  const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
   const [isModalVisible, setIsModalVisible] = useState(false);
   const [searchParams, setSearchParams] = useState({
     page: 1,

+ 34 - 45
client/admin/pages_settings.tsx

@@ -1,20 +1,14 @@
-import React, { useState, useEffect } from 'react';
+import React, { useEffect } from 'react';
 import { 
-  Layout, Menu, Button, Table, Space,
+  Button,Space,
   Form, Input, Select, message, Modal,
-  Card, Spin, Row, Col, Breadcrumb, Avatar,
-  Dropdown, ConfigProvider, theme, Typography,
-  Switch, Badge, Image, Upload, Divider, Descriptions,
-  Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer, InputNumber,ColorPicker,
-  Popover
+  Card, Spin, Typography,
+  Switch, Tabs, Alert, InputNumber
 } from 'antd';
 import {
-  UploadOutlined,
   ReloadOutlined,
   SaveOutlined,
-  BgColorsOutlined
 } from '@ant-design/icons';
-import { debounce } from 'lodash';
 import { 
   useQuery,
   useMutation,
@@ -25,25 +19,20 @@ import weekday from 'dayjs/plugin/weekday';
 import localeData from 'dayjs/plugin/localeData';
 import 'dayjs/locale/zh-cn';
 import type { 
-  FileLibrary, FileCategory, KnowInfo, SystemSetting, SystemSettingValue,
-  ColorScheme
+  SystemSetting, SystemSettingValue
 } from '../share/types.ts';
-import { ThemeMode } from '../share/types.ts';
 
 import {
   SystemSettingGroup,
   SystemSettingKey,
-  FontSize,
-  CompactMode, 
   AllowedFileType
 } from '../share/types.ts';
 
 
-import { getEnumOptions } from './utils.ts';
 
 import {
-  SystemAPI,
-} from './api.ts';
+  SystemAPI
+} from './api/index.ts';
 
 import { useTheme } from './hooks_sys.tsx';
 
@@ -241,44 +230,44 @@ export const SettingsPage = () => {
             items={Object.values(SystemSettingGroup).map(group => ({
               key: group,
               label: String(GROUP_TITLES[group]),
-              children: (
-                <div>
-                  <Alert
+                children: (
+                  <div>
+                    <Alert
                     message={GROUP_DESCRIPTIONS[group]}
-                    type="info"
-                    showIcon
-                    style={{ marginBottom: 24 }}
-                  />
-                  <Form
-                    form={form}
-                    layout="vertical"
-                    onFinish={handleSubmit}
-                  >
+                      type="info"
+                      showIcon
+                      style={{ marginBottom: 24 }}
+                    />
+                    <Form
+                      form={form}
+                      layout="vertical"
+                      onFinish={handleSubmit}
+                    >
                     {settingsData
                       ?.find(g => g.name === group)
                       ?.settings.map(setting => (
-                        <Form.Item
+                      <Form.Item
                           key={setting.key}
                           label={setting.description || setting.key}
                           name={setting.key}
                           rules={[{ required: true, message: `请输入${setting.description || setting.key}` }]}
                         >
                           {renderSettingInput(setting)}
-                        </Form.Item>
+                      </Form.Item>
                       ))}
-                    <Form.Item>
-                      <Button 
-                        type="primary" 
-                        htmlType="submit"
-                        icon={<SaveOutlined />}
-                        loading={updateSettingsMutation.isPending}
-                      >
-                        保存设置
-                      </Button>
-                    </Form.Item>
-                  </Form>
-                </div>
-              )
+                      <Form.Item>
+                        <Button
+                          type="primary"
+                          htmlType="submit"
+                          icon={<SaveOutlined />}
+                          loading={updateSettingsMutation.isPending}
+                        >
+                          保存设置
+                        </Button>
+                      </Form.Item>
+                    </Form>
+                  </div>
+                )
             }))}
           />
         </Spin>

+ 0 - 115
client/admin/pages_theme_setting.test.tsx

@@ -1,115 +0,0 @@
-import { JSDOM } from 'jsdom'
-import React from 'react'
-import {render, fireEvent, within, screen} from '@testing-library/react'
-import { ThemeSettingsPage } from "./pages_theme_settings.tsx"
-import { ThemeProvider } from "./hooks_sys.tsx"
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
-import {
-  assertEquals,
-  assertExists,
-  assertNotEquals,
-  assertRejects,
-} from "https://deno.land/std@0.217.0/assert/mod.ts";
-
-const queryClient = new QueryClient()
-
-
-const dom = new JSDOM(`<body></body>`, { 
-  runScripts: "dangerously",
-  pretendToBeVisual: true,
-  url: "http://localhost"
-});
-
-// 模拟浏览器环境
-globalThis.window = dom.window;
-globalThis.document = dom.window.document;
-
-// 定义浏览器环境所需的类
-globalThis.Element = dom.window.Element;
-globalThis.HTMLElement = dom.window.HTMLElement;
-globalThis.ShadowRoot = dom.window.ShadowRoot;
-globalThis.SVGElement = dom.window.SVGElement;
-
-// 模拟 getComputedStyle
-globalThis.getComputedStyle = (elt) => {
-  const style = new dom.window.CSSStyleDeclaration();
-  style.getPropertyValue = () => '';
-  return style;
-};
-
-// 模拟matchMedia函数
-globalThis.matchMedia = (query) => ({
-  matches: query.includes('max-width'),
-  media: query,
-  onchange: null,
-  addListener: () => {},
-  removeListener: () => {},
-  addEventListener: () => {},
-  removeEventListener: () => {},
-  dispatchEvent: () => false,
-});
-
-// 模拟动画相关API
-globalThis.AnimationEvent = globalThis.AnimationEvent || dom.window.Event;
-globalThis.TransitionEvent = globalThis.TransitionEvent || dom.window.Event;
-
-// 模拟requestAnimationFrame
-globalThis.requestAnimationFrame = globalThis.requestAnimationFrame || ((cb) => setTimeout(cb, 0));
-globalThis.cancelAnimationFrame = globalThis.cancelAnimationFrame || clearTimeout;
-
-// 设置浏览器尺寸相关方法
-window.resizeTo = (width, height) => {
-  window.innerWidth = width || window.innerWidth;
-  window.innerHeight = height || window.innerHeight;
-  window.dispatchEvent(new Event('resize'));
-};
-window.scrollTo = () => {};
-
-const customScreen = within(document.body);
-
-// 使用异步测试处理真实API调用
-Deno.test('主题设置页面测试', async (t) => {
-  // 渲染组件
-  const {findByRole, debug} = render(
-    <QueryClientProvider client={queryClient}>
-      <ThemeProvider>
-        <ThemeSettingsPage />
-      </ThemeProvider>
-    </QueryClientProvider>
-  )
-
-  // debug(await findByRole('radio', { name: /浅色模式/i }))
-
-  // 测试1: 渲染基本元素
-  await t.step('应渲染主题设置标题', async () => {
-    const title = await customScreen.findByText(/主题设置/i)
-    assertExists(title, '未找到主题设置标题')
-  })
-
-  // 测试2: 表单初始化状态
-  await t.step('表单应正确初始化', async () => {
-    // 检查主题模式选择
-    const lightRadio = await customScreen.findByRole('radio', { name: /浅色模式/i })
-    assertExists(lightRadio, '未找到浅色模式单选按钮')
-    
-    // 检查主题模式标签
-    const themeModeLabel = await customScreen.findByText(/主题模式/i)
-    assertExists(themeModeLabel, '未找到主题模式标签')
-    
-    // // 检查主题模式选择器 - Ant Design 使用 div 包裹 radio 而不是 radiogroup
-    // const themeModeField = await customScreen.findByTestId('theme-mode-selector')
-    // assertExists(themeModeField, '未找到主题模式选择器')
-  })
-
-  // 测试3: 配色方案选择
-  await t.step('应显示配色方案选项', async () => {
-    // 查找预设配色方案标签
-    const colorSchemeLabel = await customScreen.findByText('预设配色方案')
-    assertExists(colorSchemeLabel, '未找到预设配色方案标签')
-    
-    // 查找配色方案按钮
-    const colorSchemeButtons = await customScreen.findAllByRole('button')
-    assertNotEquals(colorSchemeButtons.length, 0, '未找到配色方案按钮')
-  })
-})
-

+ 5 - 28
client/admin/pages_theme_settings.tsx

@@ -1,53 +1,30 @@
 import React, { useState, useEffect } from 'react';
 import { 
-  Layout, Menu, Button, Table, Space,
-  Form, Input, Select, message, Modal,
-  Card, Spin, Row, Col, Breadcrumb, Avatar,
-  Dropdown, ConfigProvider, theme, Typography,
-  Switch, Badge, Image, Upload, Divider, Descriptions,
-  Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer, InputNumber,ColorPicker,
-  Popover
+  Button, Space,
+  Form, message, 
+  Card, Spin, Typography,
+  Switch, 
+  Popconfirm, Radio, InputNumber,ColorPicker,
 } from 'antd';
-import {
-  UploadOutlined,
-  ReloadOutlined,
-  SaveOutlined,
-  BgColorsOutlined
-} from '@ant-design/icons';
-import { debounce } from 'lodash';
-import { 
-  useQuery,
-  useMutation,
-  useQueryClient,
-} from '@tanstack/react-query';
 import dayjs from 'dayjs';
 import weekday from 'dayjs/plugin/weekday';
 import localeData from 'dayjs/plugin/localeData';
 import 'dayjs/locale/zh-cn';
 import type { 
-  FileLibrary, FileCategory, KnowInfo, SystemSetting, SystemSettingValue,
   ColorScheme
 } from '../share/types.ts';
 import { ThemeMode } from '../share/types.ts';
 
 import {
-  SystemSettingGroup,
-  SystemSettingKey,
   FontSize,
   CompactMode, 
-  AllowedFileType
 } from '../share/types.ts';
 
 
-import { getEnumOptions } from './utils.ts';
 
-import {
-  SystemAPI,
-} from './api.ts';
 
 import { useTheme } from './hooks_sys.tsx';
 
-import { Uploader } from './components_uploader.tsx';
 
 // 配置 dayjs 插件
 dayjs.extend(weekday);

+ 270 - 0
client/admin/pages_users.tsx

@@ -0,0 +1,270 @@
+import React, { useState } from 'react';
+import { 
+  Button, Table, Space, Form, Input, Select, 
+  message, Modal, Card, Typography, Tag, Popconfirm 
+} from 'antd';
+import { useQuery } from '@tanstack/react-query';
+import dayjs from 'dayjs';
+import { UserAPI } from './api/index.ts';
+
+const { Title } = Typography;
+
+// 用户管理页面
+export const UsersPage = () => {
+  const [searchParams, setSearchParams] = useState({
+    page: 1,
+    limit: 10,
+    search: ''
+  });
+  const [modalVisible, setModalVisible] = useState(false);
+  const [modalTitle, setModalTitle] = useState('');
+  const [editingUser, setEditingUser] = useState<any>(null);
+  const [form] = Form.useForm();
+
+  const { data: usersData, isLoading, refetch } = useQuery({
+    queryKey: ['users', searchParams],
+    queryFn: async () => {
+      return await UserAPI.getUsers(searchParams);
+    }
+  });
+
+  const users = usersData?.data || [];
+  const pagination = {
+    current: searchParams.page,
+    pageSize: searchParams.limit,
+    total: usersData?.pagination?.total || 0
+  };
+
+  // 处理搜索
+  const handleSearch = (values: any) => {
+    setSearchParams(prev => ({
+      ...prev,
+      search: values.search || '',
+      page: 1
+    }));
+  };
+
+  // 处理分页变化
+  const handleTableChange = (newPagination: any) => {
+    setSearchParams(prev => ({
+      ...prev,
+      page: newPagination.current,
+      limit: newPagination.pageSize
+    }));
+  };
+
+  // 打开创建用户模态框
+  const showCreateModal = () => {
+    setModalTitle('创建用户');
+    setEditingUser(null);
+    form.resetFields();
+    setModalVisible(true);
+  };
+
+  // 打开编辑用户模态框
+  const showEditModal = (user: any) => {
+    setModalTitle('编辑用户');
+    setEditingUser(user);
+    form.setFieldsValue(user);
+    setModalVisible(true);
+  };
+
+  // 处理模态框确认
+  const handleModalOk = async () => {
+    try {
+      const values = await form.validateFields();
+      
+      if (editingUser) {
+        // 编辑用户
+        await UserAPI.updateUser(editingUser.id, values);
+        message.success('用户更新成功');
+      } else {
+        // 创建用户
+        await UserAPI.createUser(values);
+        message.success('用户创建成功');
+      }
+      
+      setModalVisible(false);
+      form.resetFields();
+      refetch(); // 刷新用户列表
+    } catch (error) {
+      console.error('表单提交失败:', error);
+      message.error('操作失败,请重试');
+    }
+  };
+
+  // 处理删除用户
+  const handleDelete = async (id: number) => {
+    try {
+      await UserAPI.deleteUser(id);
+      message.success('用户删除成功');
+      refetch(); // 刷新用户列表
+    } catch (error) {
+      console.error('删除用户失败:', error);
+      message.error('删除失败,请重试');
+    }
+  };
+  
+  const columns = [
+    {
+      title: '用户名',
+      dataIndex: 'username',
+      key: 'username',
+    },
+    {
+      title: '昵称',
+      dataIndex: 'nickname',
+      key: 'nickname',
+    },
+    {
+      title: '邮箱',
+      dataIndex: 'email',
+      key: 'email',
+    },
+    {
+      title: '角色',
+      dataIndex: 'role',
+      key: 'role',
+      render: (role: string) => (
+        <Tag color={role === 'admin' ? 'red' : 'blue'}>
+          {role === 'admin' ? '管理员' : '普通用户'}
+        </Tag>
+      ),
+    },
+    {
+      title: '创建时间',
+      dataIndex: 'created_at',
+      key: 'created_at',
+      render: (date: string) => dayjs(date).format('YYYY-MM-DD HH:mm:ss'),
+    },
+    {
+      title: '操作',
+      key: 'action',
+      render: (_: any, record: any) => (
+        <Space size="middle">
+          <Button type="link" onClick={() => showEditModal(record)}>
+            编辑
+          </Button>
+          <Popconfirm
+            title="确定要删除此用户吗?"
+            onConfirm={() => handleDelete(record.id)}
+            okText="确定"
+            cancelText="取消"
+          >
+            <Button type="link" danger>
+              删除
+            </Button>
+          </Popconfirm>
+        </Space>
+      ),
+    },
+  ];
+  
+  return (
+    <div>
+      <Title level={2}>用户管理</Title>
+      <Card>
+        <Form layout="inline" onFinish={handleSearch} style={{ marginBottom: 16 }}>
+          <Form.Item name="search" label="搜索">
+            <Input placeholder="用户名/昵称/邮箱" allowClear />
+          </Form.Item>
+          <Form.Item>
+            <Space>
+              <Button type="primary" htmlType="submit">
+                搜索
+              </Button>
+              <Button type="primary" onClick={showCreateModal}>
+                创建用户
+              </Button>
+            </Space>
+          </Form.Item>
+        </Form>
+
+        <Table
+          columns={columns}
+          dataSource={users}
+          loading={isLoading}
+          rowKey="id"
+          pagination={{
+            ...pagination,
+            showSizeChanger: true,
+            showQuickJumper: true,
+            showTotal: (total) => `共 ${total} 条记录`
+          }}
+          onChange={handleTableChange}
+        />
+      </Card>
+
+      {/* 创建/编辑用户模态框 */}
+      <Modal
+        title={modalTitle}
+        open={modalVisible}
+        onOk={handleModalOk}
+        onCancel={() => {
+          setModalVisible(false);
+          form.resetFields();
+        }}
+        width={600}
+      >
+        <Form
+          form={form}
+          layout="vertical"
+        >
+          <Form.Item
+            name="username"
+            label="用户名"
+            rules={[
+              { required: true, message: '请输入用户名' },
+              { min: 3, message: '用户名至少3个字符' }
+            ]}
+          >
+            <Input placeholder="请输入用户名" />
+          </Form.Item>
+
+          <Form.Item
+            name="nickname"
+            label="昵称"
+            rules={[{ required: true, message: '请输入昵称' }]}
+          >
+            <Input placeholder="请输入昵称" />
+          </Form.Item>
+
+          <Form.Item
+            name="email"
+            label="邮箱"
+            rules={[
+              { required: true, message: '请输入邮箱' },
+              { type: 'email', message: '请输入有效的邮箱地址' }
+            ]}
+          >
+            <Input placeholder="请输入邮箱" />
+          </Form.Item>
+
+          {!editingUser && (
+            <Form.Item
+              name="password"
+              label="密码"
+              rules={[
+                { required: true, message: '请输入密码' },
+                { min: 6, message: '密码至少6个字符' }
+              ]}
+            >
+              <Input.Password placeholder="请输入密码" />
+            </Form.Item>
+          )}
+
+          <Form.Item
+            name="role"
+            label="角色"
+            rules={[{ required: true, message: '请选择角色' }]}
+          >
+            <Select placeholder="请选择角色">
+              <Select.Option value="user">普通用户</Select.Option>
+              <Select.Option value="admin">管理员</Select.Option>
+            </Select>
+          </Form.Item>
+        </Form>
+      </Modal>
+    </div>
+  );
+};

+ 7 - 3
client/admin/web_app.tsx

@@ -55,10 +55,14 @@ import {
 } from './hooks_sys.tsx';
 
 import {
-  DashboardPage,
-  UsersPage,
+  DashboardPage
+} from './pages_dashboard.tsx';
+import {
+  UsersPage
+} from './pages_users.tsx';
+import {
   FileLibraryPage
-} from './pages_sys.tsx';
+} from './pages_file_library.tsx';
 import { KnowInfoPage } from './pages_know_info.tsx';
 import { MessagesPage } from './pages_messages.tsx';
 import {SettingsPage } from './pages_settings.tsx';

+ 0 - 861
client/mobile/api.ts

@@ -1,861 +0,0 @@
-import axios from 'axios';
-import type { MinioUploadPolicy, OSSUploadPolicy } from '@d8d-appcontainer/types';
-import 'dayjs/locale/zh-cn';
-import type { 
-  User, FileLibrary, FileCategory, ThemeSettings,
-  SystemSetting, SystemSettingGroupData, 
-  LoginLocation, LoginLocationDetail,
-  MessageType, MessageStatus, UserMessage,
-  KnowInfo
-} from '../share/types.ts';
-
-
-
-// 定义API基础URL
-const API_BASE_URL = '/api';
-
-// 获取OSS完整URL
-export const getOssUrl = (path: string): string => {
-  // 获取全局配置中的OSS_HOST,如果不存在使用默认值
-  const ossHost = (window.CONFIG?.OSS_BASE_URL) || '';
-  // 确保path不以/开头
-  const ossPath = path.startsWith('/') ? path.substring(1) : path;
-  return `${ossHost}/${ossPath}`;
-};
-
-// ===================
-// Auth API 定义部分
-// ===================
-
-// 定义API返回数据类型
-interface AuthLoginResponse {
-  message: string;
-  token: string;
-  refreshToken?: string;
-  user: User;
-}
-
-interface AuthResponse {
-  message: string;
-  [key: string]: any;
-}
-
-// 定义Auth API接口类型
-interface AuthAPIType {
-  login: (username: string, password: string, latitude?: number, longitude?: number) => Promise<AuthLoginResponse>;
-  register: (username: string, email: string, password: string) => Promise<AuthResponse>;
-  logout: () => Promise<AuthResponse>;
-  getCurrentUser: () => Promise<User>;
-  updateUser: (userId: number, userData: Partial<User>) => Promise<User>;
-  changePassword: (oldPassword: string, newPassword: string) => Promise<AuthResponse>;
-  requestPasswordReset: (email: string) => Promise<AuthResponse>;
-  resetPassword: (token: string, newPassword: string) => Promise<AuthResponse>;
-}
-
-
-// Auth相关API
-export const AuthAPI: AuthAPIType = {
-  // 登录API
-  login: async (username: string, password: string, latitude?: number, longitude?: number) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/login`, {
-        username,
-        password,
-        latitude,
-        longitude
-      });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 注册API
-  register: async (username: string, email: string, password: string) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/register`, { username, email, password });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 登出API
-  logout: async () => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/logout`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 获取当前用户信息
-  getCurrentUser: async () => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/auth/me`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 更新用户信息
-  updateUser: async (userId: number, userData: Partial<User>) => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/auth/users/${userId}`, userData);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 修改密码
-  changePassword: async (oldPassword: string, newPassword: string) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/change-password`, { oldPassword, newPassword });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 请求重置密码
-  requestPasswordReset: async (email: string) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/request-password-reset`, { email });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 重置密码
-  resetPassword: async (token: string, newPassword: string) => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/auth/reset-password`, { token, newPassword });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 为UserAPI添加的接口响应类型
-interface UsersResponse {
-  data: User[];
-  pagination: {
-    total: number;
-    current: number;
-    pageSize: number;
-    totalPages: number;
-  };
-}
-
-export interface UserResponse {
-  data: User;
-  message?: string;
-}
-
-interface UserCreateResponse {
-  message: string;
-  data: User;
-}
-
-interface UserUpdateResponse {
-  message: string;
-  data: User;
-}
-
-interface UserDeleteResponse {
-  message: string;
-  id: number;
-}
-
-// 用户管理API
-export const UserAPI = {
-  // 获取用户列表
-  getUsers: async (params?: { page?: number, limit?: number, search?: string }): Promise<UsersResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/users`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 获取单个用户详情
-  getUser: async (userId: number): Promise<UserResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/users/${userId}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 创建用户
-  createUser: async (userData: Partial<User>): Promise<UserCreateResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/users`, userData);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 更新用户信息
-  updateUser: async (userId: number, userData: Partial<User>): Promise<UserUpdateResponse> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/users/${userId}`, userData);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 删除用户
-  deleteUser: async (userId: number): Promise<UserDeleteResponse> => {
-    try {
-      const response = await axios.delete(`${API_BASE_URL}/users/${userId}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 获取当前用户信息
-  getCurrentUser: async (): Promise<UserResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/users/me/profile`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-  
-  // 更新当前用户信息
-  updateCurrentUser: async (userData: Partial<User>): Promise<UserUpdateResponse> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/users/me/profile`, userData);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 定义文件相关接口类型
-interface FileUploadPolicyResponse {
-  message: string;
-  data: MinioUploadPolicy | OSSUploadPolicy;
-}
-
-interface FileListResponse {
-  message: string;
-  data: {
-    list: FileLibrary[];
-    pagination: {
-      current: number;
-      pageSize: number;
-      total: number;
-    };
-  };
-}
-
-interface FileSaveResponse {
-  message: string;
-  data: FileLibrary;
-}
-
-interface FileInfoResponse {
-  message: string;
-  data: FileLibrary;
-}
-
-interface FileDeleteResponse {
-  message: string;
-}
-
-
-interface FileCategoryListResponse {
-  data: FileCategory[];
-  total: number;
-  page: number;
-  pageSize: number;
-}
-
-interface FileCategoryCreateResponse {
-  message: string;
-  data: FileCategory;
-}
-
-interface FileCategoryUpdateResponse {
-  message: string;
-  data: FileCategory;
-}
-
-interface FileCategoryDeleteResponse {
-  message: string;
-}
-
-// 文件API接口定义
-export const FileAPI = {
-  // 获取文件上传策略
-  getUploadPolicy: async (filename: string, prefix: string = 'uploads/', maxSize: number = 10 * 1024 * 1024): Promise<FileUploadPolicyResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/upload/policy`, { 
-        params: { filename, prefix, maxSize } 
-      });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 保存文件信息
-  saveFileInfo: async (fileData: Partial<FileLibrary>): Promise<FileSaveResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/upload/save`, fileData);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取文件列表
-  getFileList: async (params?: {
-    page?: number,
-    pageSize?: number,
-    category_id?: number,
-    fileType?: string,
-    keyword?: string
-  }): Promise<FileListResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/upload/list`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取单个文件信息
-  getFileInfo: async (id: number): Promise<FileInfoResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/upload/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新文件下载计数
-  updateDownloadCount: async (id: number): Promise<FileDeleteResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/upload/${id}/download`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 删除文件
-  deleteFile: async (id: number): Promise<FileDeleteResponse> => {
-    try {
-      const response = await axios.delete(`${API_BASE_URL}/upload/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取文件分类列表
-  getCategories: async (params?: {
-    page?: number,
-    pageSize?: number,
-    search?: string
-  }): Promise<FileCategoryListResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/file-categories`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 创建文件分类
-  createCategory: async (data: Partial<FileCategory>): Promise<FileCategoryCreateResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/file-categories`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新文件分类
-  updateCategory: async (id: number, data: Partial<FileCategory>): Promise<FileCategoryUpdateResponse> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/file-categories/${id}`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 删除文件分类
-  deleteCategory: async (id: number): Promise<FileCategoryDeleteResponse> => {
-    try {
-      const response = await axios.delete(`${API_BASE_URL}/file-categories/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-
-// Theme API 定义
-export const ThemeAPI = {
-  // 获取主题设置
-  getThemeSettings: async (): Promise<ThemeSettings> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/theme`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新主题设置
-  updateThemeSettings: async (themeData: Partial<ThemeSettings>): Promise<ThemeSettings> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/theme`, themeData);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 重置主题设置
-  resetThemeSettings: async (): Promise<ThemeSettings> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/theme/reset`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 图表数据API接口类型
-interface ChartDataResponse<T> {
-  message: string;
-  data: T;
-}
-
-interface UserActivityData {
-  date: string;
-  count: number;
-}
-
-interface FileUploadsData {
-  month: string;
-  count: number;
-}
-
-interface FileTypesData {
-  type: string;
-  value: number;
-}
-
-interface DashboardOverviewData {
-  userCount: number;
-  fileCount: number;
-  articleCount: number;
-  todayLoginCount: number;
-}
-
-// 图表数据API
-export const ChartAPI = {
-  // 获取用户活跃度数据
-  getUserActivity: async (): Promise<ChartDataResponse<UserActivityData[]>> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/charts/user-activity`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取文件上传统计数据
-  getFileUploads: async (): Promise<ChartDataResponse<FileUploadsData[]>> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/charts/file-uploads`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取文件类型分布数据
-  getFileTypes: async (): Promise<ChartDataResponse<FileTypesData[]>> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/charts/file-types`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取仪表盘概览数据
-  getDashboardOverview: async (): Promise<ChartDataResponse<DashboardOverviewData>> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/charts/dashboard-overview`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-// 首页API相关类型定义
-interface HomeBannersResponse {
-  message: string;
-  data: KnowInfo[];
-}
-
-interface HomeNewsResponse {
-  message: string;
-  data: KnowInfo[];
-  pagination: {
-    total: number;
-    current: number;
-    pageSize: number;
-    totalPages: number;
-  };
-}
-
-interface HomeNoticesResponse {
-  message: string;
-    data: {
-      id: number;
-      title: string;
-      content: string;
-      created_at: string;
-    }[];
-  pagination: {
-    total: number;
-    current: number;
-    pageSize: number;
-    totalPages: number;
-  };
-}
-
-// 首页API
-export const HomeAPI = {
-  // 获取轮播图
-  getBanners: async (): Promise<HomeBannersResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/home/banners`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取新闻列表
-  getNews: async (params?: {
-    page?: number,
-    pageSize?: number,
-    category?: string
-  }): Promise<HomeNewsResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/home/news`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取通知列表
-  getNotices: async (params?: {
-    page?: number,
-    pageSize?: number
-  }): Promise<HomeNoticesResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/home/notices`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 地图相关API的接口类型定义
-export interface LoginLocationResponse {
-  message: string;
-  data: LoginLocation[];
-}
-
-export interface LoginLocationDetailResponse {
-  message: string;
-  data: LoginLocationDetail;
-}
-
-export interface LoginLocationUpdateResponse {
-  message: string;
-  data: LoginLocationDetail;
-}
-
-
-// 地图相关API
-export const MapAPI = {
-  // 获取地图标记点数据
-  getMarkers: async (params?: { 
-    startTime?: string; 
-    endTime?: string; 
-    userId?: number 
-  }): Promise<LoginLocationResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/map/markers`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取登录位置详情
-  getLocationDetail: async (locationId: number): Promise<LoginLocationDetailResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/map/location/${locationId}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 更新登录位置信息
-  updateLocation: async (locationId: number, data: { 
-    longitude: number; 
-    latitude: number; 
-    location_name?: string; 
-  }): Promise<LoginLocationUpdateResponse> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/map/location/${locationId}`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// 系统设置API
-export const SystemAPI = {
-  // 获取所有系统设置
-  getSettings: async (): Promise<SystemSettingGroupData[]> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/settings`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取指定分组的系统设置
-  getSettingsByGroup: async (group: string): Promise<SystemSetting[]> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/settings/group/${group}`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-    
-  },
-
-  // 更新系统设置
-  updateSettings: async (settings: Partial<SystemSetting>[]): Promise<SystemSetting[]> => {
-    try {
-      const response = await axios.put(`${API_BASE_URL}/settings`, settings);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 重置系统设置
-  resetSettings: async (): Promise<SystemSetting[]> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/settings/reset`);
-      return response.data.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-
-// 消息API响应类型
-export interface MessageResponse {
-  message: string;
-  data?: any;
-}
-
-export interface MessagesResponse {
-  data: UserMessage[];
-  pagination: {
-    total: number;
-    current: number;
-    pageSize: number;
-    totalPages: number;
-  };
-}
-
-export interface UnreadCountResponse {
-  count: number;
-}
-
-// 消息API
-export const MessageAPI = {
-  // 获取消息列表
-  getMessages: async (params?: {
-    page?: number,
-    pageSize?: number,
-    type?: MessageType,
-    status?: MessageStatus
-  }): Promise<MessagesResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/messages`, { params });
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取消息详情
-  getMessage: async (id: number): Promise<MessageResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/messages/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 发送消息
-  sendMessage: async (data: {
-    title: string,
-    content: string,
-    type: MessageType,
-    receiver_ids: number[]
-  }): Promise<MessageResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/messages`, data);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 删除消息(软删除)
-  deleteMessage: async (id: number): Promise<MessageResponse> => {
-    try {
-      const response = await axios.delete(`${API_BASE_URL}/messages/${id}`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 获取未读消息数量
-  getUnreadCount: async (): Promise<UnreadCountResponse> => {
-    try {
-      const response = await axios.get(`${API_BASE_URL}/messages/count/unread`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  },
-
-  // 标记消息为已读
-  markAsRead: async (id: number): Promise<MessageResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/messages/${id}/read`);
-      return response.data;
-    } catch (error) {
-      throw error;
-    }
-  }
-};
-
-// Token API 相关类型定义
-interface IMTokenResponse {
-  nonce: string;
-  token: string;
-  appId: string;
-  appSign: string;
-  timestamp: number;
-}
-
-interface RTCTokenResponse {
-  token: string;
-  appId: string;
-  timestamp: number;
-}
-
-interface TokenError {
-  message: string;
-  code?: number;
-}
-
-// Token相关API
-export const TokenAPI = {
-  /**
-   * 获取IM Token
-   * @param userId 用户ID
-   * @param role 用户角色 (admin/student)
-   * @returns Promise<string> 返回IM Token
-   * @throws {TokenError} 获取失败时抛出错误
-   */
-  getIMToken: async (userId: string, role: string): Promise<IMTokenResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/classroom/im_token`, {
-        userId,
-        role
-      });
-
-      if (!response.data.token) {
-        throw new Error('Invalid token response');
-      }
-
-      return response.data;
-    } catch (error) {
-      console.error('Failed to get IM token:', error);
-      throw new Error('Failed to get IM token');
-    }
-  },
-
-  /**
-   * 获取RTC Token
-   * @param channelId 频道ID
-   * @param userId 用户ID
-   * @returns Promise<string> 返回RTC Token
-   * @throws {TokenError} 获取失败时抛出错误
-   */
-  getRTCToken: async (channelId: string, userId: string): Promise<RTCTokenResponse> => {
-    try {
-      const response = await axios.post(`${API_BASE_URL}/classroom/rtc_token`, {
-        channelId,
-        userId
-      });
-
-      if (!response.data.token) {
-        throw new Error('Invalid token response');
-      }
-
-      return response.data;
-    } catch (error) {
-      console.error('Failed to get RTC token:', error);
-      throw new Error('Failed to get RTC token');
-    }
-  }
-};