diff --git a/client/mobile/api/auth.ts b/client/mobile/api/auth.ts new file mode 100644 index 0000000..133b0cf --- /dev/null +++ b/client/mobile/api/auth.ts @@ -0,0 +1,115 @@ +import axios from 'axios'; +import type { User } from '../../share/types.ts'; + +// 定义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; + register: (username: string, email: string, password: string) => Promise; + logout: () => Promise; + getCurrentUser: () => Promise; + updateUser: (userId: number, userData: Partial) => Promise; + changePassword: (oldPassword: string, newPassword: string) => Promise; + requestPasswordReset: (email: string) => Promise; + resetPassword: (token: string, newPassword: string) => Promise; +} + +// Auth相关API +export const AuthAPI: AuthAPIType = { + // 登录API + 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; + } + }, + + // 注册API + 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; + } + }, + + // 登出API + 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) => { + 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; + } + } +}; \ No newline at end of file diff --git a/client/mobile/api/chart.ts b/client/mobile/api/chart.ts new file mode 100644 index 0000000..3dacc16 --- /dev/null +++ b/client/mobile/api/chart.ts @@ -0,0 +1,72 @@ +import axios from 'axios'; + +// 图表数据API接口类型 +interface ChartDataResponse { + 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> => { + try { + const response = await axios.get('/charts/user-activity'); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取文件上传统计数据 + getFileUploads: async (): Promise> => { + try { + const response = await axios.get('/charts/file-uploads'); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取文件类型分布数据 + getFileTypes: async (): Promise> => { + try { + const response = await axios.get('/charts/file-types'); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取仪表盘概览数据 + getDashboardOverview: async (): Promise> => { + try { + const response = await axios.get('/charts/dashboard-overview'); + return response.data; + } catch (error) { + throw error; + } + } +}; \ No newline at end of file diff --git a/client/mobile/api/file.ts b/client/mobile/api/file.ts new file mode 100644 index 0000000..8f57603 --- /dev/null +++ b/client/mobile/api/file.ts @@ -0,0 +1,173 @@ +import axios from 'axios'; +import type { MinioUploadPolicy, OSSUploadPolicy } from '@d8d-appcontainer/types'; +import type { + FileLibrary, FileCategory +} from '../../share/types.ts'; + +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 => { + try { + const response = await axios.get('/upload/policy', { + params: { filename, prefix, maxSize } + }); + return response.data; + } catch (error) { + throw error; + } + }, + + // 保存文件信息 + saveFileInfo: async (fileData: Partial): Promise => { + 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 => { + try { + const response = await axios.get('/upload/list', { params }); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取单个文件信息 + getFileInfo: async (id: number): Promise => { + try { + const response = await axios.get(`/upload/${id}`); + return response.data; + } catch (error) { + throw error; + } + }, + + // 更新文件下载计数 + updateDownloadCount: async (id: number): Promise => { + try { + const response = await axios.post(`/upload/${id}/download`); + return response.data; + } catch (error) { + throw error; + } + }, + + // 删除文件 + deleteFile: async (id: number): Promise => { + 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 => { + try { + const response = await axios.get('/file-categories', { params }); + return response.data; + } catch (error) { + throw error; + } + }, + + // 创建文件分类 + createCategory: async (data: Partial): Promise => { + try { + const response = await axios.post('/file-categories', data); + return response.data; + } catch (error) { + throw error; + } + }, + + // 更新文件分类 + updateCategory: async (id: number, data: Partial): Promise => { + try { + const response = await axios.put(`/file-categories/${id}`, data); + return response.data; + } catch (error) { + throw error; + } + }, + + // 删除文件分类 + deleteCategory: async (id: number): Promise => { + try { + const response = await axios.delete(`/file-categories/${id}`); + return response.data; + } catch (error) { + throw error; + } + } +}; \ No newline at end of file diff --git a/client/mobile/api/home.ts b/client/mobile/api/home.ts new file mode 100644 index 0000000..cb9f183 --- /dev/null +++ b/client/mobile/api/home.ts @@ -0,0 +1,77 @@ +import axios from 'axios'; +import type { + KnowInfo +} from '../../share/types.ts'; + +// 首页数据相关类型定义 +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 => { + try { + const response = await axios.get('/home/banners'); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取新闻列表 + getNews: async (params?: { + page?: number, + pageSize?: number, + category?: string + }): Promise => { + try { + const response = await axios.get('/home/news', { params }); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取通知列表 + getNotices: async (params?: { + page?: number, + pageSize?: number + }): Promise => { + try { + const response = await axios.get('/home/notices', { params }); + return response.data; + } catch (error) { + throw error; + } + } +}; diff --git a/client/mobile/api/index.ts b/client/mobile/api/index.ts new file mode 100644 index 0000000..ede55d8 --- /dev/null +++ b/client/mobile/api/index.ts @@ -0,0 +1,25 @@ +import axios from 'axios'; + +// 基础配置 +const API_BASE_URL = '/api'; +// 全局axios配置 +axios.defaults.baseURL = API_BASE_URL; + +export * from './auth.ts'; +export * from './user.ts'; +export * from './file.ts'; +export * from './theme.ts'; +export * from './chart.ts'; +export * from './home.ts'; +export * from './map.ts'; +export * from './system.ts'; +export * from './message.ts'; + +// 获取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}`; +}; \ No newline at end of file diff --git a/client/mobile/api/map.ts b/client/mobile/api/map.ts new file mode 100644 index 0000000..4bbd731 --- /dev/null +++ b/client/mobile/api/map.ts @@ -0,0 +1,62 @@ +import axios from 'axios'; +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 => { + try { + const response = await axios.get('/map/markers', { params }); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取登录位置详情 + getLocationDetail: async (locationId: number): Promise => { + try { + const response = await axios.get(`/map/location/${locationId}`); + return response.data; + } catch (error) { + throw error; + } + }, + + // 更新登录位置信息 + updateLocation: async (locationId: number, data: { + longitude: number; + latitude: number; + location_name?: string; + }): Promise => { + try { + const response = await axios.put(`/map/location/${locationId}`, data); + return response.data; + } catch (error) { + throw error; + } + } +}; \ No newline at end of file diff --git a/client/mobile/api/message.ts b/client/mobile/api/message.ts new file mode 100644 index 0000000..5dec986 --- /dev/null +++ b/client/mobile/api/message.ts @@ -0,0 +1,97 @@ +import axios from 'axios'; +import type { + MessageType, MessageStatus, UserMessage +} from '../../share/types.ts'; + +// 消息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 => { + try { + const response = await axios.get('/messages', { params }); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取消息详情 + getMessage: async (id: number): Promise => { + try { + const response = await axios.get(`/messages/${id}`); + return response.data; + } catch (error) { + throw error; + } + }, + + // 发送消息 + sendMessage: async (data: { + title: string, + content: string, + type: MessageType, + receiver_ids: number[] + }): Promise => { + try { + const response = await axios.post('/messages', data); + return response.data; + } catch (error) { + throw error; + } + }, + + // 删除消息(软删除) + deleteMessage: async (id: number): Promise => { + try { + const response = await axios.delete(`/messages/${id}`); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取未读消息数量 + getUnreadCount: async (): Promise => { + try { + const response = await axios.get('/messages/count/unread'); + return response.data; + } catch (error) { + throw error; + } + }, + + // 标记消息为已读 + markAsRead: async (id: number): Promise => { + try { + const response = await axios.post(`/messages/${id}/read`); + return response.data; + } catch (error) { + throw error; + } + } +}; diff --git a/client/mobile/api/system.ts b/client/mobile/api/system.ts new file mode 100644 index 0000000..0ef9328 --- /dev/null +++ b/client/mobile/api/system.ts @@ -0,0 +1,48 @@ +import axios from 'axios'; +import type { + SystemSetting, SystemSettingGroupData, +} from '../../share/types.ts'; + +// 系统设置API +export const SystemAPI = { + // 获取所有系统设置 + getSettings: async (): Promise => { + try { + const response = await axios.get('/settings'); + return response.data.data; + } catch (error) { + throw error; + } + }, + + // 获取指定分组的系统设置 + getSettingsByGroup: async (group: string): Promise => { + try { + const response = await axios.get(`/settings/group/${group}`); + return response.data.data; + } catch (error) { + throw error; + } + + }, + + // 更新系统设置 + updateSettings: async (settings: Partial[]): Promise => { + try { + const response = await axios.put('/settings', settings); + return response.data.data; + } catch (error) { + throw error; + } + }, + + // 重置系统设置 + resetSettings: async (): Promise => { + try { + const response = await axios.post('/settings/reset'); + return response.data.data; + } catch (error) { + throw error; + } + } +}; \ No newline at end of file diff --git a/client/mobile/api/theme.ts b/client/mobile/api/theme.ts new file mode 100644 index 0000000..4488833 --- /dev/null +++ b/client/mobile/api/theme.ts @@ -0,0 +1,37 @@ +import axios from 'axios'; +import type { + ThemeSettings +} from '../../share/types.ts'; + +// Theme API 定义 +export const ThemeAPI = { + // 获取主题设置 + getThemeSettings: async (): Promise => { + try { + const response = await axios.get('/theme'); + return response.data.data; + } catch (error) { + throw error; + } + }, + + // 更新主题设置 + updateThemeSettings: async (themeData: Partial): Promise => { + try { + const response = await axios.put('/theme', themeData); + return response.data.data; + } catch (error) { + throw error; + } + }, + + // 重置主题设置 + resetThemeSettings: async (): Promise => { + try { + const response = await axios.post('/theme/reset'); + return response.data.data; + } catch (error) { + throw error; + } + } +}; \ No newline at end of file diff --git a/client/mobile/api/user.ts b/client/mobile/api/user.ts new file mode 100644 index 0000000..09b2dce --- /dev/null +++ b/client/mobile/api/user.ts @@ -0,0 +1,106 @@ +import axios from 'axios'; +import type { User } from '../../share/types.ts'; + +// 为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 => { + try { + const response = await axios.get('/users', { params }); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取单个用户详情 + getUser: async (userId: number): Promise => { + try { + const response = await axios.get(`/users/${userId}`); + return response.data; + } catch (error) { + throw error; + } + }, + + // 创建用户 + createUser: async (userData: Partial): Promise => { + try { + const response = await axios.post('/users', userData); + return response.data; + } catch (error) { + throw error; + } + }, + + // 更新用户信息 + updateUser: async (userId: number, userData: Partial): Promise => { + try { + const response = await axios.put(`/users/${userId}`, userData); + return response.data; + } catch (error) { + throw error; + } + }, + + // 删除用户 + deleteUser: async (userId: number): Promise => { + try { + const response = await axios.delete(`/users/${userId}`); + return response.data; + } catch (error) { + throw error; + } + }, + + // 获取当前用户信息 + getCurrentUser: async (): Promise => { + try { + const response = await axios.get('/users/me/profile'); + return response.data; + } catch (error) { + throw error; + } + }, + + // 更新当前用户信息 + updateCurrentUser: async (userData: Partial): Promise => { + try { + const response = await axios.put('/users/me/profile', userData); + return response.data; + } catch (error) { + throw error; + } + } +}; \ No newline at end of file diff --git a/client/mobile/components_uploader.tsx b/client/mobile/components_uploader.tsx index 464a787..00a3f27 100644 --- a/client/mobile/components_uploader.tsx +++ b/client/mobile/components_uploader.tsx @@ -15,7 +15,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 = ({ diff --git a/client/mobile/hooks.tsx b/client/mobile/hooks.tsx index 7d22e62..4291a3e 100644 --- a/client/mobile/hooks.tsx +++ b/client/mobile/hooks.tsx @@ -4,7 +4,7 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; import { getLocalStorageWithExpiry, setLocalStorageWithExpiry } from './utils.ts'; import type { User, AuthContextType, ThemeContextType, ThemeSettings } from '../share/types.ts'; import { ThemeMode, FontSize, CompactMode } from '../share/types.ts'; -import { AuthAPI, ThemeAPI } from './api.ts'; +import { AuthAPI, ThemeAPI } from './api/index.ts'; // 默认主题设置 const defaultThemeSettings: ThemeSettings = { diff --git a/client/mobile/pages_index.tsx b/client/mobile/pages_index.tsx index d24d316..ce15845 100644 --- a/client/mobile/pages_index.tsx +++ b/client/mobile/pages_index.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { useNavigate, useLocation } from 'react-router'; -import { HomeAPI } from './api.ts'; -import { MessageAPI } from './api.ts'; +import { HomeAPI } from './api/index.ts'; +import { MessageAPI } from './api/index.ts'; import { HomeIcon, UserIcon, diff --git a/client/mobile/pages_messages.tsx b/client/mobile/pages_messages.tsx index b4b711f..a476c41 100644 --- a/client/mobile/pages_messages.tsx +++ b/client/mobile/pages_messages.tsx @@ -7,7 +7,7 @@ import { MessageStatus } from '../share/types.ts'; // 添加通知页面组件 -import { MessageAPI } from './api.ts'; +import { MessageAPI } from './api/index.ts'; export const NotificationsPage = () => { const queryClient = useQueryClient(); diff --git a/client/mobile/pages_profile.tsx b/client/mobile/pages_profile.tsx index 681fb13..d22bc77 100644 --- a/client/mobile/pages_profile.tsx +++ b/client/mobile/pages_profile.tsx @@ -2,7 +2,7 @@ import React from 'react' import { useNavigate } from 'react-router' import { useForm } from 'react-hook-form' import { useQuery, useMutation } from '@tanstack/react-query' -import { UserAPI } from './api.ts' +import { UserAPI } from './api/index.ts' import type { User } from '../share/types.ts' import { useAuth } from './hooks.tsx' diff --git a/client/mobile/pages_register.tsx b/client/mobile/pages_register.tsx index 263310e..d3f104a 100644 --- a/client/mobile/pages_register.tsx +++ b/client/mobile/pages_register.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { useNavigate } from 'react-router'; import { ArrowRightIcon, EnvelopeIcon, LockClosedIcon, UserIcon } from '@heroicons/react/24/outline'; -import { AuthAPI } from './api.ts'; +import { AuthAPI } from './api/index.ts'; import { handleApiError } from './utils.ts'; const RegisterPage: React.FC = () => { diff --git a/client/mobile/pages_settings.tsx b/client/mobile/pages_settings.tsx index 8a581e4..2e61fd5 100644 --- a/client/mobile/pages_settings.tsx +++ b/client/mobile/pages_settings.tsx @@ -1,9 +1,9 @@ import React from 'react' import { useForm } from 'react-hook-form' import { useMutation, useQuery } from '@tanstack/react-query' -import { UserAPI } from './api.ts' +import { UserAPI } from './api/index.ts' import type { User } from '../share/types.ts' -import type { UserResponse } from './api.ts' +import type { UserResponse } from './api/index.ts' export default function SettingsPage() { const { data: userResponse, isLoading } = useQuery({