feat(image): 新建 knowai-core:1.0.0 镜像并完成推送
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
- 搭建 api、auth、utils 等逻辑模块 - 通过 tsc、eslint、vitest 测试验证 BREAKING CHANGE: 新镜像分支
This commit is contained in:
57
api/README.md
Normal file
57
api/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# API 模块
|
||||
|
||||
## 概述
|
||||
|
||||
API 模块提供统一的HTTP客户端和API请求处理功能,支持模块化的API端点管理。
|
||||
|
||||
## 核心组件
|
||||
|
||||
1. **API 客户端 (client.ts)**
|
||||
- 基于Axios的HTTP客户端
|
||||
- 提供统一的请求和响应处理
|
||||
- 支持请求拦截器和响应拦截器
|
||||
|
||||
2. **API 工厂 (factory.ts)**
|
||||
- 创建API客户端实例
|
||||
- 配置默认请求选项
|
||||
- 提供单例模式确保全局一致性
|
||||
|
||||
3. **API 模块 (modules/)**
|
||||
- 按功能模块组织API端点
|
||||
- 提供类型安全的API方法
|
||||
- 包含用户、聊天等业务模块
|
||||
|
||||
4. **类型定义 (types.d.ts)**
|
||||
- 定义API相关的接口和类型
|
||||
- 包含请求配置和响应格式
|
||||
|
||||
5. **错误处理 (errors.ts)**
|
||||
- 定义API相关的错误类
|
||||
- 提供错误处理和转换功能
|
||||
|
||||
## 使用方法
|
||||
|
||||
```typescript
|
||||
import { createApiClient } from './api';
|
||||
|
||||
// 创建API客户端
|
||||
const apiClient = createApiClient({
|
||||
baseURL: 'https://api.example.com',
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
// 使用API模块
|
||||
import { userApi } from './api/modules/user';
|
||||
|
||||
// 获取用户信息
|
||||
const user = await userApi.getUser('userId');
|
||||
|
||||
// 更新用户信息
|
||||
await userApi.updateUser('userId', { name: 'New Name' });
|
||||
```
|
||||
|
||||
## 设计模式
|
||||
|
||||
- **工厂模式**:创建API客户端实例
|
||||
- **单例模式**:确保API客户端全局唯一
|
||||
- **模块化模式**:按功能组织API端点
|
||||
279
api/client.ts
Normal file
279
api/client.ts
Normal file
@@ -0,0 +1,279 @@
|
||||
import axios from 'axios';
|
||||
import type { ApiClient } from './types';
|
||||
import type { AxiosError, AxiosResponse, AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';
|
||||
import { ApiError } from './errors'; // 直接导入ApiError
|
||||
|
||||
// 创建API客户端实例的工厂函数
|
||||
const createApiClientInstance = (config?: Partial<AxiosRequestConfig>): ApiClient => {
|
||||
// 创建axios实例
|
||||
const instance = axios.create({
|
||||
baseURL: '/api', // Core层使用默认值,具体配置由Runtime层注入
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
withCredentials: true, // 允许跨域携带cookie
|
||||
...config // 应用传入的配置
|
||||
});
|
||||
|
||||
// 请求拦截器数组
|
||||
const requestInterceptors: Array<number> = [];
|
||||
|
||||
// 响应拦截器数组
|
||||
const responseInterceptors: Array<number> = [];
|
||||
|
||||
// 添加请求拦截器
|
||||
const addRequestInterceptor = (
|
||||
onFulfilled?: (_config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,
|
||||
onRejected?: (_error: unknown) => unknown
|
||||
): number => {
|
||||
const handler = instance.interceptors.request.use(onFulfilled, onRejected);
|
||||
requestInterceptors.push(handler);
|
||||
return handler;
|
||||
};
|
||||
|
||||
// 添加响应拦截器
|
||||
const addResponseInterceptor = (
|
||||
onFulfilled?: (_response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,
|
||||
onRejected?: (_error: unknown) => unknown
|
||||
): number => {
|
||||
const handler = instance.interceptors.response.use(onFulfilled, onRejected);
|
||||
responseInterceptors.push(handler);
|
||||
return handler;
|
||||
};
|
||||
|
||||
// 移除请求拦截器
|
||||
const removeRequestInterceptor = (handler: number): void => {
|
||||
const index = requestInterceptors.indexOf(handler);
|
||||
if (index !== -1) {
|
||||
instance.interceptors.request.eject(handler);
|
||||
requestInterceptors.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
// 移除响应拦截器
|
||||
const removeResponseInterceptor = (handler: number): void => {
|
||||
const index = responseInterceptors.indexOf(handler);
|
||||
if (index !== -1) {
|
||||
instance.interceptors.response.eject(handler);
|
||||
responseInterceptors.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
// 设置默认配置
|
||||
const setDefaults = (_config: Partial<AxiosRequestConfig>): void => {
|
||||
Object.assign(instance.defaults, _config);
|
||||
};
|
||||
|
||||
// 更新基础URL - 专门用于Runtime层配置
|
||||
const setBaseURL = (baseURL: string): void => {
|
||||
instance.defaults.baseURL = baseURL;
|
||||
};
|
||||
|
||||
// 创建新实例 - 用于跨域请求等特殊场景
|
||||
const createInstance = (config?: Partial<AxiosRequestConfig>): ApiClient => {
|
||||
// 创建新的axios实例
|
||||
const newInstance = axios.create({
|
||||
...instance.defaults,
|
||||
...config
|
||||
});
|
||||
|
||||
// 为新实例创建拦截器数组
|
||||
const newRequestInterceptors: Array<number> = [];
|
||||
const newResponseInterceptors: Array<number> = [];
|
||||
|
||||
// 复制拦截器
|
||||
requestInterceptors.forEach(handler => {
|
||||
// 由于AxiosInterceptorManager类型定义中没有handlers属性,
|
||||
// 我们使用类型断言来访问内部属性
|
||||
type RequestHandlerType = {
|
||||
id: number;
|
||||
fulfilled: (_config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
|
||||
rejected: (_error: unknown) => unknown;
|
||||
};
|
||||
|
||||
type RequestManagerType = {
|
||||
handlers?: Array<RequestHandlerType>;
|
||||
};
|
||||
|
||||
const requestManager = instance.interceptors.request as unknown as RequestManagerType;
|
||||
const originalInterceptor = requestManager.handlers?.find((h: RequestHandlerType) => h.id === handler);
|
||||
if (originalInterceptor) {
|
||||
const newHandler = newInstance.interceptors.request.use(
|
||||
originalInterceptor.fulfilled,
|
||||
originalInterceptor.rejected
|
||||
);
|
||||
newRequestInterceptors.push(newHandler);
|
||||
}
|
||||
});
|
||||
|
||||
responseInterceptors.forEach(handler => {
|
||||
// 由于AxiosInterceptorManager类型定义中没有handlers属性,
|
||||
// 我们使用类型断言来访问内部属性
|
||||
type ResponseHandlerType = {
|
||||
id: number;
|
||||
fulfilled: (_response: AxiosResponse) => AxiosResponse;
|
||||
rejected: (_error: AxiosError) => unknown;
|
||||
};
|
||||
|
||||
type ResponseManagerType = {
|
||||
handlers?: Array<ResponseHandlerType>;
|
||||
};
|
||||
|
||||
const responseManager = instance.interceptors.response as unknown as ResponseManagerType;
|
||||
const originalInterceptor = responseManager.handlers?.find((h: ResponseHandlerType) => h.id === handler);
|
||||
if (originalInterceptor) {
|
||||
const newHandler = newInstance.interceptors.response.use(
|
||||
originalInterceptor.fulfilled,
|
||||
originalInterceptor.rejected
|
||||
);
|
||||
newResponseInterceptors.push(newHandler);
|
||||
}
|
||||
});
|
||||
|
||||
// 返回一个符合ApiClient接口的对象
|
||||
return {
|
||||
request: async <T = unknown>(config: AxiosRequestConfig): Promise<T> => {
|
||||
try {
|
||||
const response = await newInstance.request<T>(config);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
// 直接使用ApiError.fromAxiosError静态方法处理错误
|
||||
return Promise.reject(ApiError.fromAxiosError(error as AxiosError));
|
||||
}
|
||||
},
|
||||
get: <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return newInstance.request<T>({ ...config, method: 'GET', url }).then((res: AxiosResponse<T>) => res.data);
|
||||
},
|
||||
post: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return newInstance.request<T>({ ...config, method: 'POST', url, data }).then((res: AxiosResponse<T>) => res.data);
|
||||
},
|
||||
put: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return newInstance.request<T>({ ...config, method: 'PUT', url, data }).then((res: AxiosResponse<T>) => res.data);
|
||||
},
|
||||
delete: <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return newInstance.request<T>({ ...config, method: 'DELETE', url }).then((res: AxiosResponse<T>) => res.data);
|
||||
},
|
||||
patch: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return newInstance.request<T>({ ...config, method: 'PATCH', url, data }).then((res: AxiosResponse<T>) => res.data);
|
||||
},
|
||||
setDefaults: (_config: Partial<AxiosRequestConfig>): void => {
|
||||
Object.assign(newInstance.defaults, _config);
|
||||
},
|
||||
setBaseURL: (baseURL: string): void => {
|
||||
newInstance.defaults.baseURL = baseURL;
|
||||
},
|
||||
createInstance: (newConfig?: Partial<AxiosRequestConfig>): ApiClient => {
|
||||
// 手动处理headers字段的类型转换
|
||||
const { headers, ...otherDefaults } = newInstance.defaults;
|
||||
const configWithTypedHeaders: Partial<AxiosRequestConfig> = {
|
||||
...otherDefaults,
|
||||
...newConfig
|
||||
};
|
||||
|
||||
// 只有当headers存在时才添加
|
||||
if (headers) {
|
||||
// 手动转换headers字段,确保类型安全
|
||||
const convertedHeaders: Record<string, string | number | boolean> = {};
|
||||
Object.entries(headers).forEach(([key, value]) => {
|
||||
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
||||
convertedHeaders[key] = value;
|
||||
}
|
||||
});
|
||||
configWithTypedHeaders.headers = convertedHeaders;
|
||||
}
|
||||
|
||||
return createInstance(configWithTypedHeaders);
|
||||
},
|
||||
addRequestInterceptor: (
|
||||
onFulfilled?: (_config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,
|
||||
onRejected?: (_error: unknown) => unknown
|
||||
): number => {
|
||||
const handler = newInstance.interceptors.request.use(onFulfilled, onRejected);
|
||||
newRequestInterceptors.push(handler);
|
||||
return handler;
|
||||
},
|
||||
addResponseInterceptor: (
|
||||
onFulfilled?: (_response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,
|
||||
onRejected?: (_error: unknown) => unknown
|
||||
): number => {
|
||||
const handler = newInstance.interceptors.response.use(onFulfilled, onRejected);
|
||||
newResponseInterceptors.push(handler);
|
||||
return handler;
|
||||
},
|
||||
removeRequestInterceptor: (handler: number): void => {
|
||||
const index = newRequestInterceptors.indexOf(handler);
|
||||
if (index !== -1) {
|
||||
newInstance.interceptors.request.eject(handler);
|
||||
newRequestInterceptors.splice(index, 1);
|
||||
}
|
||||
},
|
||||
removeResponseInterceptor: (handler: number): void => {
|
||||
const index = newResponseInterceptors.indexOf(handler);
|
||||
if (index !== -1) {
|
||||
newInstance.interceptors.response.eject(handler);
|
||||
newResponseInterceptors.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 基础请求方法
|
||||
const request = async <T = unknown>(config: AxiosRequestConfig): Promise<T> => {
|
||||
try {
|
||||
const response = await instance.request<T>(config);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
// 直接使用ApiError.fromAxiosError静态方法处理错误
|
||||
return Promise.reject(ApiError.fromAxiosError(error as AxiosError));
|
||||
}
|
||||
};
|
||||
|
||||
// HTTP方法简写
|
||||
const get = <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return request<T>({ ...config, method: 'GET', url });
|
||||
};
|
||||
|
||||
const post = <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return request<T>({ ...config, method: 'POST', url, data });
|
||||
};
|
||||
|
||||
const put = <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return request<T>({ ...config, method: 'PUT', url, data });
|
||||
};
|
||||
|
||||
const del = <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return request<T>({ ...config, method: 'DELETE', url });
|
||||
};
|
||||
|
||||
const patch = <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
|
||||
return request<T>({ ...config, method: 'PATCH', url, data });
|
||||
};
|
||||
|
||||
return {
|
||||
request,
|
||||
get,
|
||||
post,
|
||||
put,
|
||||
delete: del,
|
||||
patch,
|
||||
setDefaults,
|
||||
setBaseURL,
|
||||
createInstance,
|
||||
addRequestInterceptor,
|
||||
addResponseInterceptor,
|
||||
removeRequestInterceptor,
|
||||
removeResponseInterceptor
|
||||
};
|
||||
};
|
||||
|
||||
// 默认实例(单例)
|
||||
const apiClient = createApiClientInstance();
|
||||
|
||||
// 工厂函数
|
||||
const createApiClient = (config?: Partial<AxiosRequestConfig>) => {
|
||||
return createApiClientInstance(config);
|
||||
};
|
||||
|
||||
// 导出API客户端和工厂函数
|
||||
export { apiClient, createApiClient };
|
||||
46
api/errors.ts
Normal file
46
api/errors.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* API错误处理
|
||||
*/
|
||||
import type { AxiosError } from 'axios';
|
||||
|
||||
/**
|
||||
* API错误接口
|
||||
*/
|
||||
export interface IApiError {
|
||||
code: number;
|
||||
message: string;
|
||||
details?: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* API错误类
|
||||
*/
|
||||
export class ApiError extends Error implements IApiError {
|
||||
public readonly code: number;
|
||||
public readonly details: unknown;
|
||||
|
||||
constructor(code: number, message: string, details?: unknown) {
|
||||
super(message);
|
||||
this.name = 'ApiError';
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Axios错误创建API错误
|
||||
*/
|
||||
static fromAxiosError(error: AxiosError): ApiError {
|
||||
if (!error.response) {
|
||||
return new ApiError(0, error.message || '网络错误');
|
||||
}
|
||||
|
||||
const { status, data } = error.response;
|
||||
const message = data && typeof data === 'object' && 'message' in data
|
||||
? data.message as string
|
||||
: '请求失败';
|
||||
|
||||
return new ApiError(status, message, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
api/factory.ts
Normal file
40
api/factory.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { apiClient, createApiClient } from './client';
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
import { postApi } from './modules/post';
|
||||
import { userApi } from './modules/user';
|
||||
import { chatApi } from './modules/chat';
|
||||
import { modelApi } from './modules/model';
|
||||
|
||||
/**
|
||||
* API 工厂函数,用于创建和管理 API 实例
|
||||
* 提供统一的 API 访问入口和配置管理
|
||||
*/
|
||||
export const createApi = (config?: Partial<AxiosRequestConfig>) => {
|
||||
const client = config ? createApiClient(config) : apiClient;
|
||||
|
||||
return {
|
||||
// 核心客户端
|
||||
client,
|
||||
|
||||
// API 模块 - 使用提供的客户端或默认客户端
|
||||
modules: {
|
||||
post: postApi(client),
|
||||
user: userApi(client),
|
||||
chat: chatApi(client),
|
||||
model: modelApi(client)
|
||||
},
|
||||
|
||||
// 便捷访问
|
||||
post: postApi(client),
|
||||
user: userApi(client),
|
||||
chat: chatApi(client),
|
||||
model: modelApi(client)
|
||||
};
|
||||
};
|
||||
|
||||
// 导出默认 API 实例
|
||||
export const api = createApi();
|
||||
|
||||
// 向后兼容的导出
|
||||
export { apiClient } from './client';
|
||||
export { postApi, userApi, chatApi, modelApi } from './modules';
|
||||
19
api/index.ts
Normal file
19
api/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// 导出API工厂函数和默认实例
|
||||
export { createApi, api } from './factory';
|
||||
|
||||
// 导出API类型和配置
|
||||
export {
|
||||
API_ENDPOINTS,
|
||||
ApiStatusCode,
|
||||
ApiErrorType,
|
||||
DEFAULT_REQUEST_CONFIG,
|
||||
DEFAULT_PAGINATION_CONFIG,
|
||||
type ApiClient,
|
||||
type ApiResponse,
|
||||
type PaginatedResponse,
|
||||
type ErrorResponse
|
||||
} from './types';
|
||||
|
||||
// 向后兼容的导出
|
||||
export { apiClient } from './client';
|
||||
export { postApi, userApi, chatApi, modelApi } from './modules';
|
||||
48
api/modules/chat.ts
Normal file
48
api/modules/chat.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
import type { ApiClient } from '../types';
|
||||
import type {
|
||||
CreateChatSessionRequest,
|
||||
UpdateChatSessionRequest,
|
||||
SendMessageRequest,
|
||||
GetChatSessionsRequest,
|
||||
GetChatSessionsResponse,
|
||||
GetChatMessagesRequest,
|
||||
GetChatMessagesResponse,
|
||||
MarkMessagesAsReadRequest,
|
||||
MarkMessagesAsReadResponse
|
||||
} from '@/types/chat/api';
|
||||
import type { ChatSession, ChatMessage } from '@/types/chat/base';
|
||||
|
||||
// 聊天API服务工厂函数
|
||||
export const chatApi = (client: ApiClient) => ({
|
||||
// 创建聊天会话
|
||||
createSession: (data: CreateChatSessionRequest): Promise<{ session: ChatSession }> => {
|
||||
return client.post('/chat/sessions', data);
|
||||
},
|
||||
|
||||
// 更新聊天会话
|
||||
updateSession: ({ sessionId, ...data }: UpdateChatSessionRequest): Promise<{ session: ChatSession }> => {
|
||||
return client.put(`/chat/sessions/${sessionId}`, data);
|
||||
},
|
||||
|
||||
// 发送消息
|
||||
sendMessage: (data: SendMessageRequest): Promise<{ message: ChatMessage }> => {
|
||||
return client.post(`/chat/sessions/${data.sessionId}/messages`, data);
|
||||
},
|
||||
|
||||
// 获取聊天会话列表
|
||||
getSessions: (params?: GetChatSessionsRequest): Promise<GetChatSessionsResponse> => {
|
||||
const config: AxiosRequestConfig = params ? { params } : {};
|
||||
return client.get('/chat/sessions', config);
|
||||
},
|
||||
|
||||
// 获取聊天消息
|
||||
getMessages: ({ sessionId, ...params }: GetChatMessagesRequest): Promise<GetChatMessagesResponse> => {
|
||||
return client.get(`/chat/sessions/${sessionId}/messages`, { params });
|
||||
},
|
||||
|
||||
// 标记消息已读
|
||||
markMessagesAsRead: ({ sessionId, messageIds }: MarkMessagesAsReadRequest): Promise<MarkMessagesAsReadResponse> => {
|
||||
return client.post(`/chat/sessions/${sessionId}/read`, { messageIds });
|
||||
}
|
||||
});
|
||||
14
api/modules/index.ts
Normal file
14
api/modules/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { apiClient } from '../client';
|
||||
import { postApi as createPostApi } from './post';
|
||||
import { userApi as createUserApi } from './user';
|
||||
import { chatApi as createChatApi } from './chat';
|
||||
import { modelApi as createModelApi } from './model';
|
||||
|
||||
// 导出工厂函数
|
||||
export { postApi as createPostApi, userApi as createUserApi, chatApi as createChatApi, modelApi as createModelApi };
|
||||
|
||||
// 向后兼容的默认实例
|
||||
export const postApi = createPostApi(apiClient);
|
||||
export const userApi = createUserApi(apiClient);
|
||||
export const chatApi = createChatApi(apiClient);
|
||||
export const modelApi = createModelApi(apiClient);
|
||||
29
api/modules/model.ts
Normal file
29
api/modules/model.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
import type { ApiClient } from '../types';
|
||||
import type {
|
||||
GetAIPlazaRequest,
|
||||
GetAIPlazaResponse,
|
||||
GetModelDetailRequest,
|
||||
GetModelDetailResponse,
|
||||
GetModelCommentsRequest,
|
||||
GetModelCommentsResponse
|
||||
} from '@/types/model/api';
|
||||
|
||||
// AI模型API服务工厂函数
|
||||
export const modelApi = (client: ApiClient) => ({
|
||||
// 获取AI模型广场数据
|
||||
getAIPlaza: (params?: GetAIPlazaRequest): Promise<GetAIPlazaResponse> => {
|
||||
const config: AxiosRequestConfig = params ? { params } : {};
|
||||
return client.get('/models/plaza', config);
|
||||
},
|
||||
|
||||
// 获取模型详情
|
||||
getModelDetail: ({ modelId, ...params }: GetModelDetailRequest): Promise<GetModelDetailResponse> => {
|
||||
return client.get(`/models/${modelId}`, { params });
|
||||
},
|
||||
|
||||
// 获取模型评论
|
||||
getModelComments: ({ modelId, ...params }: GetModelCommentsRequest): Promise<GetModelCommentsResponse> => {
|
||||
return client.get(`/models/${modelId}/comments`, { params });
|
||||
}
|
||||
});
|
||||
65
api/modules/post.ts
Normal file
65
api/modules/post.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
import type { ApiClient } from '../types';
|
||||
import type {
|
||||
CreatePostRequest,
|
||||
CreatePostResponse,
|
||||
GetPostsRequest,
|
||||
GetPostsResponse,
|
||||
GetPostRequest,
|
||||
GetPostResponse,
|
||||
LikePostRequest,
|
||||
LikePostResponse,
|
||||
BookmarkPostRequest,
|
||||
BookmarkPostResponse,
|
||||
CreateCommentRequest,
|
||||
CreateCommentResponse,
|
||||
GetCommentsRequest,
|
||||
GetCommentsResponse,
|
||||
LikeCommentRequest,
|
||||
LikeCommentResponse
|
||||
} from '@/types/post/api';
|
||||
|
||||
// 帖子API服务工厂函数
|
||||
export const postApi = (client: ApiClient) => ({
|
||||
// 创建帖子
|
||||
createPost: (data: CreatePostRequest): Promise<CreatePostResponse> => {
|
||||
return client.post('/posts', data);
|
||||
},
|
||||
|
||||
// 获取帖子列表
|
||||
getPosts: (params: GetPostsRequest): Promise<GetPostsResponse> => {
|
||||
const config: AxiosRequestConfig = { params };
|
||||
return client.get('/posts', config);
|
||||
},
|
||||
|
||||
// 获取帖子详情
|
||||
getPost: ({ postId }: GetPostRequest): Promise<GetPostResponse> => {
|
||||
return client.get(`/posts/${postId}`);
|
||||
},
|
||||
|
||||
// 点赞帖子
|
||||
likePost: ({ postId }: LikePostRequest): Promise<LikePostResponse> => {
|
||||
return client.put(`/posts/${postId}/like`);
|
||||
},
|
||||
|
||||
// 收藏帖子
|
||||
bookmarkPost: ({ postId }: BookmarkPostRequest): Promise<BookmarkPostResponse> => {
|
||||
return client.put(`/posts/${postId}/bookmark`);
|
||||
},
|
||||
|
||||
// 创建评论
|
||||
createComment: (data: CreateCommentRequest): Promise<CreateCommentResponse> => {
|
||||
return client.post(`/posts/${data.postId}/comments`, data);
|
||||
},
|
||||
|
||||
// 获取评论列表
|
||||
getComments: (params: GetCommentsRequest): Promise<GetCommentsResponse> => {
|
||||
const { postId, ...queryParams } = params;
|
||||
return client.get(`/posts/${postId}/comments`, { params: queryParams });
|
||||
},
|
||||
|
||||
// 点赞评论
|
||||
likeComment: ({ commentId }: LikeCommentRequest): Promise<LikeCommentResponse> => {
|
||||
return client.put(`/comments/${commentId}/like`);
|
||||
}
|
||||
});
|
||||
51
api/modules/user.ts
Normal file
51
api/modules/user.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import type { ApiClient } from '../types';
|
||||
import type {
|
||||
LoginRequest,
|
||||
LoginResponse,
|
||||
RegisterRequest,
|
||||
RegisterResponse,
|
||||
RefreshTokenRequest,
|
||||
RefreshTokenResponse,
|
||||
UserProfileUpdateRequest,
|
||||
UserProfileUpdateResponse,
|
||||
UserFollowRequest,
|
||||
UserFollowResponse
|
||||
} from '@/types/user';
|
||||
|
||||
// 用户API服务工厂函数
|
||||
export const userApi = (client: ApiClient) => ({
|
||||
// 用户登录
|
||||
login: (data: LoginRequest): Promise<LoginResponse> => {
|
||||
return client.post('/auth/login', data);
|
||||
},
|
||||
|
||||
// 用户注册
|
||||
register: (data: RegisterRequest): Promise<RegisterResponse> => {
|
||||
return client.post('/auth/register', data);
|
||||
},
|
||||
|
||||
// 刷新令牌
|
||||
refreshToken: (data: RefreshTokenRequest): Promise<RefreshTokenResponse> => {
|
||||
return client.post('/auth/refresh', data);
|
||||
},
|
||||
|
||||
// 获取用户档案
|
||||
getProfile: (): Promise<UserProfileUpdateResponse> => {
|
||||
return client.get('/user/profile');
|
||||
},
|
||||
|
||||
// 更新用户档案
|
||||
updateProfile: (data: UserProfileUpdateRequest): Promise<UserProfileUpdateResponse> => {
|
||||
return client.put('/user/profile', data);
|
||||
},
|
||||
|
||||
// 关注用户
|
||||
followUser: ({ userId }: UserFollowRequest): Promise<UserFollowResponse> => {
|
||||
return client.put(`/user/follow/${userId}`);
|
||||
},
|
||||
|
||||
// 取消关注用户
|
||||
unfollowUser: ({ userId }: UserFollowRequest): Promise<UserFollowResponse> => {
|
||||
return client.delete(`/user/follow/${userId}`);
|
||||
}
|
||||
});
|
||||
119
api/types.d.ts
vendored
Normal file
119
api/types.d.ts
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* API 类型定义文件
|
||||
*/
|
||||
|
||||
import type { AxiosResponse, AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';
|
||||
|
||||
// API客户端接口定义
|
||||
export interface ApiClient {
|
||||
request<T = unknown>(config: AxiosRequestConfig): Promise<T>;
|
||||
get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
||||
post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>;
|
||||
put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>;
|
||||
delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
||||
patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>;
|
||||
setDefaults(config: Partial<AxiosRequestConfig>): void;
|
||||
setBaseURL(baseURL: string): void;
|
||||
createInstance(config?: Partial<AxiosRequestConfig>): ApiClient;
|
||||
addRequestInterceptor(
|
||||
onFulfilled?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,
|
||||
onRejected?: (error: unknown) => unknown
|
||||
): number;
|
||||
addResponseInterceptor(
|
||||
onFulfilled?: (response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,
|
||||
onRejected?: (error: unknown) => unknown
|
||||
): number;
|
||||
removeRequestInterceptor(handler: number): void;
|
||||
removeResponseInterceptor(handler: number): void;
|
||||
}
|
||||
|
||||
// API响应接口
|
||||
export interface ApiResponse<T = unknown> {
|
||||
success: boolean;
|
||||
data: T;
|
||||
message?: string;
|
||||
code?: number;
|
||||
}
|
||||
|
||||
// 分页响应接口
|
||||
export interface PaginatedResponse<T = unknown> {
|
||||
items: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
// 错误响应接口
|
||||
export interface ErrorResponse {
|
||||
success: false;
|
||||
message: string;
|
||||
code?: number;
|
||||
details?: unknown;
|
||||
}
|
||||
|
||||
// API端点常量
|
||||
export const API_ENDPOINTS = {
|
||||
// 用户相关
|
||||
USER_LOGIN: '/auth/login',
|
||||
USER_REGISTER: '/auth/register',
|
||||
USER_LOGOUT: '/auth/logout',
|
||||
USER_PROFILE: '/user/profile',
|
||||
USER_CURRENT: '/auth/me',
|
||||
|
||||
// 聊天相关
|
||||
CHAT_LIST: '/chat/list',
|
||||
CHAT_CREATE: '/chat/create',
|
||||
CHAT_DETAIL: '/chat/detail',
|
||||
CHAT_DELETE: '/chat/delete',
|
||||
CHAT_MESSAGE: '/chat/message',
|
||||
|
||||
// 模型相关
|
||||
MODEL_LIST: '/model/list',
|
||||
MODEL_DETAIL: '/model/detail',
|
||||
|
||||
// 帖子相关
|
||||
POST_LIST: '/post/list',
|
||||
POST_DETAIL: '/post/detail',
|
||||
POST_CREATE: '/post/create',
|
||||
POST_UPDATE: '/post/update',
|
||||
POST_DELETE: '/post/delete'
|
||||
} as const;
|
||||
|
||||
// API状态码
|
||||
export const ApiStatusCode = {
|
||||
OK: 200,
|
||||
CREATED: 201,
|
||||
NO_CONTENT: 204,
|
||||
BAD_REQUEST: 400,
|
||||
UNAUTHORIZED: 401,
|
||||
FORBIDDEN: 403,
|
||||
NOT_FOUND: 404,
|
||||
INTERNAL_SERVER_ERROR: 500
|
||||
} as const;
|
||||
|
||||
// API错误类型
|
||||
export const ApiErrorType = {
|
||||
NETWORK_ERROR: 'NETWORK_ERROR',
|
||||
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
||||
AUTHENTICATION_ERROR: 'AUTHENTICATION_ERROR',
|
||||
AUTHORIZATION_ERROR: 'AUTHORIZATION_ERROR',
|
||||
NOT_FOUND_ERROR: 'NOT_FOUND_ERROR',
|
||||
SERVER_ERROR: 'SERVER_ERROR',
|
||||
UNKNOWN_ERROR: 'UNKNOWN_ERROR'
|
||||
} as const;
|
||||
|
||||
// 默认请求配置
|
||||
export const DEFAULT_REQUEST_CONFIG = {
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
withCredentials: true
|
||||
} as const;
|
||||
|
||||
// 默认分页配置
|
||||
export const DEFAULT_PAGINATION_CONFIG = {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
} as const;
|
||||
Reference in New Issue
Block a user