feat(api): 添加热门卡片与榜单接口及实现
- 新增热门帖子、热门作者、榜单接口及实现 - 新增api-documentation,更好的ai协作 - 修复types没有导出的问题 BREAKING CHANGES: 1.0.0->1.1.0(latest)
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@ node_modules
|
|||||||
|
|
||||||
# 测试与打包
|
# 测试与打包
|
||||||
coverage/
|
coverage/
|
||||||
|
dist/
|
||||||
|
|
||||||
# 编辑器
|
# 编辑器
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -26,8 +26,18 @@ API模块负责处理所有与后端通信相关的逻辑,提供统一的HTTP
|
|||||||
#### 核心功能
|
#### 核心功能
|
||||||
- **请求工厂**:使用工厂模式创建API实例,统一配置请求参数
|
- **请求工厂**:使用工厂模式创建API实例,统一配置请求参数
|
||||||
- **拦截器系统**:支持请求/响应拦截器,实现统一的错误处理、日志记录和认证
|
- **拦截器系统**:支持请求/响应拦截器,实现统一的错误处理、日志记录和认证
|
||||||
- **模块化API服务**:按功能域划分API服务,如用户API、内容API等
|
- **模块化API服务**:按功能域划分API服务,如用户API、帖子API等
|
||||||
- **响应标准化**:统一处理API响应格式,提供一致的错误处理机制
|
- **响应标准化**:统一处理API响应格式,提供一致的错误处理机制
|
||||||
|
- **内容发现**:提供热门帖子、帖子榜单和热门作者功能,支持多种排序和统计周期
|
||||||
|
|
||||||
|
#### 新增功能
|
||||||
|
##### 帖子相关
|
||||||
|
- **热门帖子**:通过`getHotPosts()`获取指定时间内的热门帖子
|
||||||
|
- **帖子榜单**:通过`getPostRanking()`获取不同周期(日/周/月)的帖子排行榜,支持按浏览量、点赞数、评论数排序
|
||||||
|
|
||||||
|
##### 用户相关
|
||||||
|
- **热门作者**:通过`getHotAuthors()`获取指定时间内的热门作者
|
||||||
|
- **作者榜单**:通过`getAuthorRanking()`获取不同周期(日/周/月)的作者排行榜,支持按发帖量、浏览量、点赞数排序
|
||||||
|
|
||||||
#### 架构特点
|
#### 架构特点
|
||||||
- 基于axios构建,支持请求/响应转换
|
- 基于axios构建,支持请求/响应转换
|
||||||
@@ -114,3 +124,13 @@ knowai-core/
|
|||||||
### 2025-11-11
|
### 2025-11-11
|
||||||
- 因服务器性能原因去除CI pipeline
|
- 因服务器性能原因去除CI pipeline
|
||||||
- 重新整理所有逻辑模块架构,完成对应README撰写
|
- 重新整理所有逻辑模块架构,完成对应README撰写
|
||||||
|
|
||||||
|
### 2025-11-12
|
||||||
|
- 实现帖子相关新功能:热门帖子、帖子榜单
|
||||||
|
- 实现用户相关新功能:热门作者、作者榜单
|
||||||
|
- 更新README文档,添加新功能说明
|
||||||
|
|
||||||
|
### 2025-11-18
|
||||||
|
- 添加热门帖子、榜单、热门作者接口
|
||||||
|
- 完成api-documentation.md文档,详细描述所有接口的功能、参数、响应格式等
|
||||||
|
- 修复类型未导出问题
|
||||||
909
api-documentation.md
Normal file
909
api-documentation.md
Normal file
@@ -0,0 +1,909 @@
|
|||||||
|
# KnowAI Core API 文档
|
||||||
|
|
||||||
|
本文档详细介绍了 KnowAI Core 库提供的 API 接口和类型定义,供 Page 层项目使用。
|
||||||
|
|
||||||
|
## 1. 库概述
|
||||||
|
|
||||||
|
KnowAI Core 是一个通用的前端核心库,提供了 API 调用、认证管理、工具函数等基础功能。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 导入方式
|
||||||
|
export * from './types'; // 类型定义
|
||||||
|
export * from './api'; // API客户端和模块
|
||||||
|
export * from './auth'; // 鉴权相关功能
|
||||||
|
export * from './utils'; // 工具函数
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. API 客户端
|
||||||
|
|
||||||
|
### 2.1 初始化 API 客户端
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createApi } from 'knowai-core';
|
||||||
|
|
||||||
|
// 创建默认 API 客户端
|
||||||
|
const api = createApi();
|
||||||
|
|
||||||
|
// 或使用自定义配置
|
||||||
|
const api = createApi({
|
||||||
|
baseURL: '/api', // 默认值
|
||||||
|
timeout: 10000,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
withCredentials: true
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 API 客户端功能
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 帖子模块 (Post)
|
||||||
|
|
||||||
|
### 3.1 API 接口
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 获取帖子API服务
|
||||||
|
const postApiService = api.post;
|
||||||
|
// 或 const postApiService = api.modules.post;
|
||||||
|
|
||||||
|
// 创建帖子
|
||||||
|
createPost(data: CreatePostRequest): Promise<CreatePostResponse>;
|
||||||
|
|
||||||
|
// 获取帖子列表
|
||||||
|
getPosts(params: GetPostsRequest): Promise<GetPostsResponse>;
|
||||||
|
|
||||||
|
// 获取帖子详情
|
||||||
|
getPost({ postId }: GetPostRequest): Promise<GetPostResponse>;
|
||||||
|
|
||||||
|
// 点赞帖子
|
||||||
|
likePost({ postId }: LikePostRequest): Promise<LikePostResponse>;
|
||||||
|
|
||||||
|
// 收藏帖子
|
||||||
|
bookmarkPost({ postId }: BookmarkPostRequest): Promise<BookmarkPostResponse>;
|
||||||
|
|
||||||
|
// 创建评论
|
||||||
|
createComment(data: CreateCommentRequest): Promise<CreateCommentResponse>;
|
||||||
|
|
||||||
|
// 获取评论列表
|
||||||
|
getComments(params: GetCommentsRequest): Promise<GetCommentsResponse>;
|
||||||
|
|
||||||
|
// 点赞评论
|
||||||
|
likeComment({ commentId }: LikeCommentRequest): Promise<LikeCommentResponse>;
|
||||||
|
|
||||||
|
// 获取热门帖子
|
||||||
|
getHotPosts(params?: GetHotPostsRequest): Promise<GetHotPostsResponse>;
|
||||||
|
|
||||||
|
// 获取帖子榜单
|
||||||
|
getPostRanking(params?: GetPostRankingRequest): Promise<GetPostRankingResponse>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 数据类型定义
|
||||||
|
|
||||||
|
#### 创建帖子请求
|
||||||
|
```typescript
|
||||||
|
export interface CreatePostRequest extends BaseEntityContent {
|
||||||
|
type: PostType; // 帖子类型:提问或文章
|
||||||
|
images?: string[]; // 图片
|
||||||
|
publishedAt?: Date; // 发布时间
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取帖子列表请求
|
||||||
|
```typescript
|
||||||
|
export interface GetPostsRequest {
|
||||||
|
page?: number; // 页码
|
||||||
|
limit?: number; // 每页数量
|
||||||
|
sortBy?: PostSortBy; // 帖子排序方式
|
||||||
|
type?: PostType; // 帖子类型:提问或文章
|
||||||
|
sortOrder?: SortOrder; // 排序方向
|
||||||
|
authorId?: string;
|
||||||
|
search?: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取帖子列表响应
|
||||||
|
```typescript
|
||||||
|
export interface GetPostsResponse {
|
||||||
|
data: Post[]; // 数据列表
|
||||||
|
total: number; // 总数
|
||||||
|
page: number; // 当前页码
|
||||||
|
limit: number; // 每页数量
|
||||||
|
hasMore: boolean; // 是否有更多数据
|
||||||
|
sortBy?: PostSortBy; // 帖子排序方式
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 帖子接口
|
||||||
|
```typescript
|
||||||
|
export interface Post extends BaseEntity, BaseEntityContent {
|
||||||
|
type: PostType; // 帖子类型:提问或文章
|
||||||
|
authorId: string; // 作者ID
|
||||||
|
author: BaseUser; // 作者信息
|
||||||
|
images?: string[]; // 图片数组
|
||||||
|
publishedAt?: Date; // 发布时间
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 基础实体内容接口
|
||||||
|
```typescript
|
||||||
|
export interface BaseEntityContent {
|
||||||
|
title?: string; // 标题
|
||||||
|
excerpt: string; // 摘要
|
||||||
|
tags?: string[]; // 标签数组
|
||||||
|
metadata?: Record<string, unknown>; // 元数据
|
||||||
|
stars: number; // 收藏数
|
||||||
|
likes: number; // 点赞数
|
||||||
|
comments: number; // 评论数
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取热门帖子请求
|
||||||
|
```typescript
|
||||||
|
export interface GetHotPostsRequest {
|
||||||
|
limit?: number; // 限制数量
|
||||||
|
days?: number; // 时间范围(天)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取热门帖子响应
|
||||||
|
```typescript
|
||||||
|
export interface GetHotPostsResponse {
|
||||||
|
data: Post[]; // 热门帖子列表
|
||||||
|
total: number; // 总数
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取帖子榜单请求
|
||||||
|
```typescript
|
||||||
|
export interface GetPostRankingRequest {
|
||||||
|
limit?: number; // 限制数量
|
||||||
|
period?: 'day' | 'week' | 'month'; // 时间周期
|
||||||
|
type?: 'views' | 'likes' | 'comments'; // 榜单类型
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取帖子榜单响应
|
||||||
|
```typescript
|
||||||
|
export interface GetPostRankingResponse {
|
||||||
|
data: Post[]; // 帖子榜单列表
|
||||||
|
total: number; // 总数
|
||||||
|
period: 'day' | 'week' | 'month'; // 时间周期
|
||||||
|
type: 'views' | 'likes' | 'comments'; // 榜单类型
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 用户模块 (User)
|
||||||
|
|
||||||
|
### 4.1 API 接口
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 获取用户API服务
|
||||||
|
const userApiService = api.user;
|
||||||
|
// 或 const userApiService = api.modules.user;
|
||||||
|
|
||||||
|
// 用户登录
|
||||||
|
login(data: LoginRequest): Promise<LoginResponse>;
|
||||||
|
|
||||||
|
// 用户注册
|
||||||
|
register(data: RegisterRequest): Promise<RegisterResponse>;
|
||||||
|
|
||||||
|
// 系统使用服务器端session管理,无需手动刷新令牌
|
||||||
|
|
||||||
|
// 获取用户档案
|
||||||
|
getProfile(): Promise<UserProfileUpdateResponse>;
|
||||||
|
|
||||||
|
// 更新用户档案
|
||||||
|
updateProfile(data: UserProfileUpdateRequest): Promise<UserProfileUpdateResponse>;
|
||||||
|
|
||||||
|
// 关注用户
|
||||||
|
followUser({ userId }: UserFollowRequest): Promise<UserFollowResponse>;
|
||||||
|
|
||||||
|
// 取消关注用户
|
||||||
|
unfollowUser({ userId }: UserFollowRequest): Promise<UserFollowResponse>;
|
||||||
|
|
||||||
|
// 获取热门作者
|
||||||
|
getHotAuthors(params?: GetHotAuthorsRequest): Promise<GetHotAuthorsResponse>;
|
||||||
|
|
||||||
|
// 获取作者榜单
|
||||||
|
getAuthorRanking(params?: GetAuthorRankingRequest): Promise<GetAuthorRankingResponse>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 数据类型定义
|
||||||
|
|
||||||
|
#### 登录请求
|
||||||
|
```typescript
|
||||||
|
export interface LoginRequest {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 登录响应
|
||||||
|
```typescript
|
||||||
|
export interface LoginResponse {
|
||||||
|
user: User;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 用户接口
|
||||||
|
```typescript
|
||||||
|
export interface User {
|
||||||
|
id: string;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取热门作者请求
|
||||||
|
```typescript
|
||||||
|
export interface GetHotAuthorsRequest {
|
||||||
|
limit?: number; // 限制数量
|
||||||
|
days?: number; // 时间范围(天)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取热门作者响应
|
||||||
|
```typescript
|
||||||
|
export interface GetHotAuthorsResponse {
|
||||||
|
data: User[]; // 热门作者列表
|
||||||
|
total: number; // 总数
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取作者榜单请求
|
||||||
|
```typescript
|
||||||
|
export interface GetAuthorRankingRequest {
|
||||||
|
limit?: number; // 限制数量
|
||||||
|
period?: 'day' | 'week' | 'month'; // 时间周期
|
||||||
|
type?: 'posts' | 'views' | 'likes'; // 榜单类型
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取作者榜单响应
|
||||||
|
```typescript
|
||||||
|
export interface GetAuthorRankingResponse {
|
||||||
|
data: User[]; // 作者榜单列表
|
||||||
|
total: number; // 总数
|
||||||
|
period: 'day' | 'week' | 'month'; // 时间周期
|
||||||
|
type: 'posts' | 'views' | 'likes'; // 榜单类型
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 聊天模块 (Chat)
|
||||||
|
|
||||||
|
### 5.1 API 接口
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 获取聊天API服务
|
||||||
|
const chatApiService = api.chat;
|
||||||
|
// 或 const chatApiService = api.modules.chat;
|
||||||
|
|
||||||
|
// 创建聊天会话
|
||||||
|
createSession(data: CreateChatSessionRequest): Promise<{ session: ChatSession }>;
|
||||||
|
|
||||||
|
// 更新聊天会话
|
||||||
|
updateSession({ sessionId, ...data }: UpdateChatSessionRequest): Promise<{ session: ChatSession }>;
|
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
sendMessage(data: SendMessageRequest): Promise<{ message: ChatMessage }>;
|
||||||
|
|
||||||
|
// 获取聊天会话列表
|
||||||
|
getSessions(params?: GetChatSessionsRequest): Promise<GetChatSessionsResponse>;
|
||||||
|
|
||||||
|
// 获取聊天消息
|
||||||
|
getMessages({ sessionId, ...params }: GetChatMessagesRequest): Promise<GetChatMessagesResponse>;
|
||||||
|
|
||||||
|
// 标记消息已读
|
||||||
|
markMessagesAsRead({ sessionId, messageIds }: MarkMessagesAsReadRequest): Promise<MarkMessagesAsReadResponse>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 数据类型定义
|
||||||
|
|
||||||
|
#### 聊天消息接口
|
||||||
|
```typescript
|
||||||
|
export interface ChatMessage {
|
||||||
|
id: string;
|
||||||
|
sessionId: string;
|
||||||
|
sender: User;
|
||||||
|
receiver: User;
|
||||||
|
content: string;
|
||||||
|
type: ChatMessageType;
|
||||||
|
status: ChatMessageStatus;
|
||||||
|
createdAt: Date;
|
||||||
|
// 非文本消息类型的元数据
|
||||||
|
metadata?: {
|
||||||
|
fileName?: string;
|
||||||
|
fileSize?: number;
|
||||||
|
duration?: number;
|
||||||
|
thumbnail?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 聊天会话接口
|
||||||
|
```typescript
|
||||||
|
export interface ChatSession {
|
||||||
|
id: string;
|
||||||
|
participant1Id: string;
|
||||||
|
participant2Id: string;
|
||||||
|
participant1: User;
|
||||||
|
participant2: User;
|
||||||
|
lastMessage?: {
|
||||||
|
id: string;
|
||||||
|
content: string;
|
||||||
|
senderId: string;
|
||||||
|
createdAt: Date;
|
||||||
|
};
|
||||||
|
unreadCount1: number; // 参与者1的未读消息数
|
||||||
|
unreadCount2: number; // 参与者2的未读消息数
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
// 会话元数据(特殊标记、背景设置、自定义属性等等)
|
||||||
|
metadata?: {
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 发送消息请求
|
||||||
|
```typescript
|
||||||
|
export interface SendMessageRequest {
|
||||||
|
sessionId: string;
|
||||||
|
content: string;
|
||||||
|
type: ChatMessageType;
|
||||||
|
metadata?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取聊天会话列表响应
|
||||||
|
```typescript
|
||||||
|
export interface GetChatSessionsResponse {
|
||||||
|
sessions: ChatSession[];
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 模型模块 (Model)
|
||||||
|
|
||||||
|
### 6.1 API 接口
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 获取模型API服务
|
||||||
|
const modelApiService = api.model;
|
||||||
|
// 或 const modelApiService = api.modules.model;
|
||||||
|
|
||||||
|
// 获取AI模型广场数据
|
||||||
|
getAIPlaza(params?: GetAIPlazaRequest): Promise<GetAIPlazaResponse>;
|
||||||
|
|
||||||
|
// 获取模型详情
|
||||||
|
getModelDetail({ modelId, ...params }: GetModelDetailRequest): Promise<GetModelDetailResponse>;
|
||||||
|
|
||||||
|
// 获取模型评论
|
||||||
|
getModelComments({ modelId, ...params }: GetModelCommentsRequest): Promise<GetModelCommentsResponse>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 数据类型定义
|
||||||
|
|
||||||
|
#### AI模型接口
|
||||||
|
```typescript
|
||||||
|
export interface AIModel {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
avatar?: string; // 模型头像
|
||||||
|
tags?: string[]; // 模型标签
|
||||||
|
website?: string; // 官方网站
|
||||||
|
clickCount?: number; // 点击次数
|
||||||
|
likeCount?: number; // 点赞次数
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### AI模型评论接口
|
||||||
|
```typescript
|
||||||
|
export interface ModelComment extends BaseEntity {
|
||||||
|
modelId: string; // 模型ID
|
||||||
|
authorId: string; // 作者ID
|
||||||
|
author: BaseUser; // 作者信息
|
||||||
|
content: string; // 评论内容
|
||||||
|
parentId?: string; // 父评论ID,用于嵌套评论
|
||||||
|
stats: ModelCommentStats; // 统计信息
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### AI模型广场响应
|
||||||
|
```typescript
|
||||||
|
export interface GetAIPlazaResponse {
|
||||||
|
models: AIModel[]; // 模型卡片列表,由管理员预定义
|
||||||
|
hotRankings: AIModelRankingItem[]; // 热评模型榜单
|
||||||
|
clickRankings: AIModelRankingItem[]; // 点击排行榜
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 模型详情响应
|
||||||
|
```typescript
|
||||||
|
export interface GetModelDetailResponse {
|
||||||
|
model: AIModel;
|
||||||
|
comments: ModelComment[]; // 使用新的ModelComment类型,已经是数组
|
||||||
|
totalComments: number;
|
||||||
|
hasMoreComments: boolean; // 是否还有更多评论,支持无限滚动加载
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. 通用数据类型
|
||||||
|
|
||||||
|
### 7.1 API 响应结构
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 标准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;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 常量定义
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 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;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 错误处理
|
||||||
|
|
||||||
|
### 8.1 API 错误处理示例
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { ApiErrorType } from 'knowai-core';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const posts = await api.post.getPosts({ page: 1, limit: 10 });
|
||||||
|
// 处理成功响应
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === ApiErrorType.AUTHENTICATION_ERROR) {
|
||||||
|
// 处理认证错误
|
||||||
|
} else if (error.code === ApiErrorType.NETWORK_ERROR) {
|
||||||
|
// 处理网络错误
|
||||||
|
} else {
|
||||||
|
// 处理其他错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. 在 Page 层项目中的使用示例
|
||||||
|
|
||||||
|
### 9.1 初始化 API 客户端和认证服务 (Nuxt 插件)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// plugins/api.ts
|
||||||
|
import { createApi, createAuthService } from 'knowai-core';
|
||||||
|
|
||||||
|
export default defineNuxtPlugin(nuxtApp => {
|
||||||
|
// 创建API客户端
|
||||||
|
const api = createApi({
|
||||||
|
baseURL: '/api',
|
||||||
|
timeout: 15000
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建认证服务
|
||||||
|
const authService = createAuthService(api.client);
|
||||||
|
|
||||||
|
// 无需手动添加认证令牌,使用浏览器的 cookie-session 机制
|
||||||
|
// 会话由服务器端控制,前端通过API查询认证状态
|
||||||
|
api.client.addRequestInterceptor(
|
||||||
|
(config) => {
|
||||||
|
// 会话由浏览器自动管理,无需手动添加认证信息
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => Promise.reject(error)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 添加响应拦截器(处理错误)
|
||||||
|
api.client.addResponseInterceptor(
|
||||||
|
(response) => response,
|
||||||
|
(error) => {
|
||||||
|
// 统一错误处理逻辑
|
||||||
|
console.error('API Error:', error);
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 提供API客户端和认证服务给Nuxt应用
|
||||||
|
nuxtApp.provide('api', api);
|
||||||
|
nuxtApp.provide('authService', authService);
|
||||||
|
|
||||||
|
// 提供模块化API服务
|
||||||
|
nuxtApp.provide('postApi', api.post);
|
||||||
|
nuxtApp.provide('userApi', api.user);
|
||||||
|
nuxtApp.provide('chatApi', api.chat);
|
||||||
|
nuxtApp.provide('modelApi', api.model);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2 在页面中使用 API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// pages/index.vue
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { useNuxtApp } from '#app';
|
||||||
|
|
||||||
|
const { $postApi, $userApi } = useNuxtApp();
|
||||||
|
const posts = ref([]);
|
||||||
|
const hotPosts = ref([]);
|
||||||
|
const postRanking = ref([]);
|
||||||
|
const hotAuthors = ref([]);
|
||||||
|
const authorRanking = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const error = ref(null);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
// 获取普通帖子列表
|
||||||
|
const response = await $postApi.getPosts({
|
||||||
|
page: 1,
|
||||||
|
limit: 10,
|
||||||
|
sortBy: 'latest'
|
||||||
|
});
|
||||||
|
posts.value = response.data;
|
||||||
|
|
||||||
|
// 获取热门帖子
|
||||||
|
const hotPostsResponse = await $postApi.getHotPosts({
|
||||||
|
limit: 5,
|
||||||
|
days: 7
|
||||||
|
});
|
||||||
|
hotPosts.value = hotPostsResponse.data;
|
||||||
|
|
||||||
|
// 获取帖子榜单(周榜,按点赞数排序)
|
||||||
|
const rankingResponse = await $postApi.getPostRanking({
|
||||||
|
limit: 10,
|
||||||
|
period: 'week',
|
||||||
|
type: 'likes'
|
||||||
|
});
|
||||||
|
postRanking.value = rankingResponse.data;
|
||||||
|
|
||||||
|
// 获取热门作者
|
||||||
|
const hotAuthorsResponse = await $userApi.getHotAuthors({
|
||||||
|
limit: 5,
|
||||||
|
days: 30
|
||||||
|
});
|
||||||
|
hotAuthors.value = hotAuthorsResponse.data;
|
||||||
|
|
||||||
|
// 获取作者榜单(月榜,按发帖量排序)
|
||||||
|
const authorRankingResponse = await $userApi.getAuthorRanking({
|
||||||
|
limit: 10,
|
||||||
|
period: 'month',
|
||||||
|
type: 'posts'
|
||||||
|
});
|
||||||
|
authorRanking.value = authorRankingResponse.data;
|
||||||
|
} catch (err) {
|
||||||
|
error.value = err;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.3 在页面中使用认证服务
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// pages/auth/login.vue
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useNuxtApp, navigateTo } from '#app';
|
||||||
|
import type { LoginRequest } from 'knowai-core';
|
||||||
|
|
||||||
|
const { $authService } = useNuxtApp();
|
||||||
|
const loginForm = ref<LoginRequest>({
|
||||||
|
username: '',
|
||||||
|
password: ''
|
||||||
|
});
|
||||||
|
const loading = ref(false);
|
||||||
|
const error = ref<string | null>(null);
|
||||||
|
|
||||||
|
// 用户登录
|
||||||
|
const handleLogin = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
error.value = null;
|
||||||
|
try {
|
||||||
|
await $authService.login(loginForm.value);
|
||||||
|
// 登录成功,跳转到首页
|
||||||
|
await navigateTo('/');
|
||||||
|
} catch (err: any) {
|
||||||
|
error.value = err.message || '登录失败,请检查用户名和密码';
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="login-form">
|
||||||
|
<h1>登录</h1>
|
||||||
|
<div v-if="error" class="error-message">{{ error }}</div>
|
||||||
|
<form @submit.prevent="handleLogin">
|
||||||
|
<div>
|
||||||
|
<label>用户名</label>
|
||||||
|
<input v-model="loginForm.username" type="text" required />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>密码</label>
|
||||||
|
<input v-model="loginForm.password" type="password" required />
|
||||||
|
</div>
|
||||||
|
<button type="submit" :disabled="loading">
|
||||||
|
{{ loading ? '登录中...' : '登录' }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.4 检查用户认证状态
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// middleware/auth.ts
|
||||||
|
import { useNuxtApp } from '#app';
|
||||||
|
|
||||||
|
export default defineNuxtRouteMiddleware(async () => {
|
||||||
|
const { $authService } = useNuxtApp();
|
||||||
|
try {
|
||||||
|
// 检查用户是否已认证
|
||||||
|
const isAuthenticated = await $authService.isAuthenticated();
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
// 未认证,跳转到登录页
|
||||||
|
return navigateTo('/auth/login');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 认证检查失败,跳转到登录页
|
||||||
|
return navigateTo('/auth/login');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 在需要认证的页面中使用
|
||||||
|
// pages/profile.vue
|
||||||
|
<script setup lang="ts">
|
||||||
|
definePageMeta({
|
||||||
|
middleware: 'auth'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面内容...
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.5 在 Pinia Store 中使用 API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// stores/postStore.ts
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { useNuxtApp } from '#app';
|
||||||
|
import type { Post, GetPostsRequest, GetPostsResponse } from 'knowai-core';
|
||||||
|
|
||||||
|
export const usePostStore = defineStore('post', () => {
|
||||||
|
const { $postApi } = useNuxtApp();
|
||||||
|
const posts = ref<Post[]>([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const error = ref<string | null>(null);
|
||||||
|
|
||||||
|
const fetchPosts = async (params: GetPostsRequest) => {
|
||||||
|
loading.value = true;
|
||||||
|
error.value = null;
|
||||||
|
try {
|
||||||
|
const response: GetPostsResponse = await $postApi.getPosts(params);
|
||||||
|
posts.value = response.data;
|
||||||
|
return response;
|
||||||
|
} catch (err) {
|
||||||
|
error.value = err.message || '获取帖子列表失败';
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
posts,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
fetchPosts
|
||||||
|
};
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.4 聊天功能使用示例
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// stores/chatStore.ts
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { useNuxtApp } from '#app';
|
||||||
|
import type { ChatSession, ChatMessage, GetChatSessionsRequest, GetChatMessagesRequest } from 'knowai-core';
|
||||||
|
|
||||||
|
export const useChatStore = defineStore('chat', () => {
|
||||||
|
const { $chatApi } = useNuxtApp();
|
||||||
|
const sessions = ref<ChatSession[]>([]);
|
||||||
|
const currentSession = ref<ChatSession | null>(null);
|
||||||
|
const messages = ref<ChatMessage[]>([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
// 获取会话列表
|
||||||
|
const fetchSessions = async (params?: GetChatSessionsRequest) => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const response = await $chatApi.getSessions(params);
|
||||||
|
sessions.value = response.sessions;
|
||||||
|
return response;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取会话消息
|
||||||
|
const fetchMessages = async (params: GetChatMessagesRequest) => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const response = await $chatApi.getMessages(params);
|
||||||
|
messages.value = response.messages;
|
||||||
|
return response;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
const sendChatMessage = async (content: string, type: ChatMessageType) => {
|
||||||
|
if (!currentSession.value) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await $chatApi.sendMessage({
|
||||||
|
sessionId: currentSession.value.id,
|
||||||
|
content,
|
||||||
|
type
|
||||||
|
});
|
||||||
|
messages.value.push(response.message);
|
||||||
|
return response.message;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
sessions,
|
||||||
|
currentSession,
|
||||||
|
messages,
|
||||||
|
loading,
|
||||||
|
fetchSessions,
|
||||||
|
fetchMessages,
|
||||||
|
sendChatMessage
|
||||||
|
};
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.5 模型模块使用示例
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// stores/modelStore.ts
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { useNuxtApp } from '#app';
|
||||||
|
import type { AIModel, ModelComment, GetModelDetailRequest } from 'knowai-core';
|
||||||
|
|
||||||
|
export const useModelStore = defineStore('model', () => {
|
||||||
|
const { $modelApi } = useNuxtApp();
|
||||||
|
const plazaData = ref<{ models: AIModel[], hotRankings: any[], clickRankings: any[] } | null>(null);
|
||||||
|
const currentModel = ref<AIModel | null>(null);
|
||||||
|
const modelComments = ref<ModelComment[]>([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
// 获取AI广场数据
|
||||||
|
const fetchAIPlaza = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const response = await $modelApi.getAIPlaza();
|
||||||
|
plazaData.value = response;
|
||||||
|
return response;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取模型详情
|
||||||
|
const fetchModelDetail = async (modelId: string) => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const response = await $modelApi.getModelDetail({ modelId });
|
||||||
|
currentModel.value = response.model;
|
||||||
|
modelComments.value = response.comments;
|
||||||
|
return response;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
plazaData,
|
||||||
|
currentModel,
|
||||||
|
modelComments,
|
||||||
|
loading,
|
||||||
|
fetchAIPlaza,
|
||||||
|
fetchModelDetail
|
||||||
|
};
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. 注意事项
|
||||||
|
|
||||||
|
1. **认证处理**:所有需要认证的接口通过浏览器的 cookie-session 机制自动处理,无需手动添加令牌,session 完全由服务器端控制
|
||||||
|
2. **错误处理**:使用 try/catch 捕获 API 调用可能出现的错误
|
||||||
|
3. **分页处理**:注意检查 `hasMore` 字段来实现分页加载
|
||||||
|
4. **数据缓存**:建议在 store 中缓存常用数据,避免重复请求
|
||||||
|
5. **类型安全**:使用 TypeScript 类型确保数据结构正确性
|
||||||
|
6. **聊天会话管理**:注意处理聊天会话中的未读消息计数
|
||||||
|
7. **模型数据**:AI广场数据是静态配置的,不需要分页参数
|
||||||
|
|
||||||
|
## 11. 完整API参考
|
||||||
|
|
||||||
|
详细的API参考请查看 `knowai-core/api/modules` 目录下的各个模块文件。
|
||||||
@@ -16,7 +16,11 @@ import type {
|
|||||||
GetCommentsRequest,
|
GetCommentsRequest,
|
||||||
GetCommentsResponse,
|
GetCommentsResponse,
|
||||||
LikeCommentRequest,
|
LikeCommentRequest,
|
||||||
LikeCommentResponse
|
LikeCommentResponse,
|
||||||
|
GetHotPostsRequest,
|
||||||
|
GetHotPostsResponse,
|
||||||
|
GetPostRankingRequest,
|
||||||
|
GetPostRankingResponse
|
||||||
} from '@/types/post/api';
|
} from '@/types/post/api';
|
||||||
|
|
||||||
// 帖子API服务工厂函数
|
// 帖子API服务工厂函数
|
||||||
@@ -61,5 +65,15 @@ export const postApi = (client: ApiClient) => ({
|
|||||||
// 点赞评论
|
// 点赞评论
|
||||||
likeComment: ({ commentId }: LikeCommentRequest): Promise<LikeCommentResponse> => {
|
likeComment: ({ commentId }: LikeCommentRequest): Promise<LikeCommentResponse> => {
|
||||||
return client.put(`/comments/${commentId}/like`);
|
return client.put(`/comments/${commentId}/like`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取热门帖子
|
||||||
|
getHotPosts: (params: GetHotPostsRequest = {}): Promise<GetHotPostsResponse> => {
|
||||||
|
return client.get('/posts/hot', { params });
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取帖子榜单
|
||||||
|
getPostRanking: (params: GetPostRankingRequest = {}): Promise<GetPostRankingResponse> => {
|
||||||
|
return client.get('/posts/ranking', { params });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ import type {
|
|||||||
UserProfileUpdateRequest,
|
UserProfileUpdateRequest,
|
||||||
UserProfileUpdateResponse,
|
UserProfileUpdateResponse,
|
||||||
UserFollowRequest,
|
UserFollowRequest,
|
||||||
UserFollowResponse
|
UserFollowResponse,
|
||||||
|
GetHotAuthorsRequest,
|
||||||
|
GetHotAuthorsResponse,
|
||||||
|
GetAuthorRankingRequest,
|
||||||
|
GetAuthorRankingResponse
|
||||||
} from '@/types/user';
|
} from '@/types/user';
|
||||||
|
|
||||||
// 用户API服务工厂函数
|
// 用户API服务工厂函数
|
||||||
@@ -47,5 +51,15 @@ export const userApi = (client: ApiClient) => ({
|
|||||||
// 取消关注用户
|
// 取消关注用户
|
||||||
unfollowUser: ({ userId }: UserFollowRequest): Promise<UserFollowResponse> => {
|
unfollowUser: ({ userId }: UserFollowRequest): Promise<UserFollowResponse> => {
|
||||||
return client.delete(`/user/follow/${userId}`);
|
return client.delete(`/user/follow/${userId}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取热门作者
|
||||||
|
getHotAuthors: (params: GetHotAuthorsRequest = {}): Promise<GetHotAuthorsResponse> => {
|
||||||
|
return client.get('/user/hot', { params });
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取作者榜单
|
||||||
|
getAuthorRanking: (params: GetAuthorRankingRequest = {}): Promise<GetAuthorRankingResponse> => {
|
||||||
|
return client.get('/user/ranking', { params });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export class DefaultSessionManager {
|
|||||||
this.currentUser = response.user;
|
this.currentUser = response.user;
|
||||||
// 如果成功获取用户信息,触发session_authenticated事件
|
// 如果成功获取用户信息,触发session_authenticated事件
|
||||||
authEventManager.emit('session_authenticated', this.currentUser);
|
authEventManager.emit('session_authenticated', this.currentUser);
|
||||||
return this.currentUser;
|
return response.user;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.currentUser = null;
|
this.currentUser = null;
|
||||||
// 如果获取用户信息失败,触发session_expired事件
|
// 如果获取用户信息失败,触发session_expired事件
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
# Types 模块
|
|
||||||
|
|
||||||
## 架构设计
|
|
||||||
|
|
||||||
Types模块用于定义前端数据模型,提供给其他模块进行API或行为封装。
|
|
||||||
|
|
||||||
## 包含
|
|
||||||
|
|
||||||
1. **chat**
|
|
||||||
- 包
|
|
||||||
@@ -111,6 +111,33 @@ export interface LikeCommentResponse {
|
|||||||
success: boolean;
|
success: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取热门帖子请求接口
|
||||||
|
export interface GetHotPostsRequest {
|
||||||
|
limit?: number; // 每页数量
|
||||||
|
days?: number; // 统计天数,默认7天
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取热门帖子响应接口
|
||||||
|
export interface GetHotPostsResponse {
|
||||||
|
data: Post[]; // 数据列表
|
||||||
|
total: number; // 总数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取帖子榜单请求接口
|
||||||
|
export interface GetPostRankingRequest {
|
||||||
|
limit?: number; // 每页数量
|
||||||
|
period?: 'day' | 'week' | 'month'; // 统计周期
|
||||||
|
type?: 'views' | 'likes' | 'comments'; // 排序类型
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取帖子榜单响应接口
|
||||||
|
export interface GetPostRankingResponse {
|
||||||
|
data: Post[]; // 数据列表
|
||||||
|
total: number; // 总数
|
||||||
|
period: 'day' | 'week' | 'month'; // 统计周期
|
||||||
|
type: 'views' | 'likes' | 'comments'; // 排序类型
|
||||||
|
}
|
||||||
|
|
||||||
// 后面全部暂时不考虑
|
// 后面全部暂时不考虑
|
||||||
// 删除帖子请求接口
|
// 删除帖子请求接口
|
||||||
export interface DeletePostRequest {
|
export interface DeletePostRequest {
|
||||||
28
types/user/api.ts
Normal file
28
types/user/api.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import type { User } from './base';
|
||||||
|
|
||||||
|
// 获取热门作者请求接口
|
||||||
|
export interface GetHotAuthorsRequest {
|
||||||
|
limit?: number; // 每页数量
|
||||||
|
days?: number; // 统计天数,默认30天
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取热门作者响应接口
|
||||||
|
export interface GetHotAuthorsResponse {
|
||||||
|
data: User[]; // 数据列表
|
||||||
|
total: number; // 总数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取作者榜单请求接口
|
||||||
|
export interface GetAuthorRankingRequest {
|
||||||
|
limit?: number; // 每页数量
|
||||||
|
period?: 'day' | 'week' | 'month'; // 统计周期
|
||||||
|
type?: 'posts' | 'views' | 'likes'; // 排序类型
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取作者榜单响应接口
|
||||||
|
export interface GetAuthorRankingResponse {
|
||||||
|
data: User[]; // 数据列表
|
||||||
|
total: number; // 总数
|
||||||
|
period: 'day' | 'week' | 'month'; // 统计周期
|
||||||
|
type: 'posts' | 'views' | 'likes'; // 排序类型
|
||||||
|
}
|
||||||
@@ -2,3 +2,4 @@ export * from './base';
|
|||||||
export * from './profile';
|
export * from './profile';
|
||||||
export * from './search';
|
export * from './search';
|
||||||
export * from './enum';
|
export * from './enum';
|
||||||
|
export * from './api';
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
// 导出所有工具函数
|
// 导出所有工具函数
|
||||||
export * from './date';
|
export * from './date';
|
||||||
export * from './string';
|
export * from './string';
|
||||||
|
export * from './number';
|
||||||
export * from './data';
|
export * from './data';
|
||||||
export * from './validation';
|
export * from './validation';
|
||||||
|
|||||||
54
utils/number.ts
Normal file
54
utils/number.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// 数字格式化工具
|
||||||
|
export const numberUtils = {
|
||||||
|
// 格式化数字,添加千分位分隔符
|
||||||
|
format: (num: number, decimalPlaces: number = 0): string => {
|
||||||
|
if (isNaN(num)) return '0';
|
||||||
|
return num.toFixed(decimalPlaces).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||||
|
},
|
||||||
|
|
||||||
|
// 格式化大数字为K、M、B等形式
|
||||||
|
formatLarge: (num: number, decimalPlaces: number = 1): string => {
|
||||||
|
if (isNaN(num)) return '0';
|
||||||
|
|
||||||
|
const thresholds = [
|
||||||
|
{ value: 1, symbol: '' },
|
||||||
|
{ value: 1000, symbol: 'K' },
|
||||||
|
{ value: 1000000, symbol: 'M' },
|
||||||
|
{ value: 1000000000, symbol: 'B' },
|
||||||
|
{ value: 1000000000000, symbol: 'T' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 找到合适的阈值
|
||||||
|
const threshold = thresholds
|
||||||
|
.reverse()
|
||||||
|
.find(threshold => num >= threshold.value);
|
||||||
|
|
||||||
|
if (!threshold) return '0';
|
||||||
|
|
||||||
|
// 计算并格式化
|
||||||
|
const result = num / threshold.value;
|
||||||
|
return `${result.toFixed(decimalPlaces)}${threshold.symbol}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 格式化数字为中文形式(万、亿等)
|
||||||
|
formatChinese: (num: number, decimalPlaces: number = 1): string => {
|
||||||
|
if (isNaN(num)) return '0';
|
||||||
|
|
||||||
|
const thresholds = [
|
||||||
|
{ value: 1, symbol: '' },
|
||||||
|
{ value: 10000, symbol: '万' },
|
||||||
|
{ value: 100000000, symbol: '亿' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 找到合适的阈值
|
||||||
|
const threshold = thresholds
|
||||||
|
.reverse()
|
||||||
|
.find(threshold => num >= threshold.value);
|
||||||
|
|
||||||
|
if (!threshold) return '0';
|
||||||
|
|
||||||
|
// 计算并格式化
|
||||||
|
const result = num / threshold.value;
|
||||||
|
return `${result.toFixed(decimalPlaces)}${threshold.symbol}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user