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/
|
||||
dist/
|
||||
|
||||
# 编辑器
|
||||
.vscode/*
|
||||
|
||||
24
README.md
24
README.md
@@ -26,8 +26,18 @@ API模块负责处理所有与后端通信相关的逻辑,提供统一的HTTP
|
||||
#### 核心功能
|
||||
- **请求工厂**:使用工厂模式创建API实例,统一配置请求参数
|
||||
- **拦截器系统**:支持请求/响应拦截器,实现统一的错误处理、日志记录和认证
|
||||
- **模块化API服务**:按功能域划分API服务,如用户API、内容API等
|
||||
- **模块化API服务**:按功能域划分API服务,如用户API、帖子API等
|
||||
- **响应标准化**:统一处理API响应格式,提供一致的错误处理机制
|
||||
- **内容发现**:提供热门帖子、帖子榜单和热门作者功能,支持多种排序和统计周期
|
||||
|
||||
#### 新增功能
|
||||
##### 帖子相关
|
||||
- **热门帖子**:通过`getHotPosts()`获取指定时间内的热门帖子
|
||||
- **帖子榜单**:通过`getPostRanking()`获取不同周期(日/周/月)的帖子排行榜,支持按浏览量、点赞数、评论数排序
|
||||
|
||||
##### 用户相关
|
||||
- **热门作者**:通过`getHotAuthors()`获取指定时间内的热门作者
|
||||
- **作者榜单**:通过`getAuthorRanking()`获取不同周期(日/周/月)的作者排行榜,支持按发帖量、浏览量、点赞数排序
|
||||
|
||||
#### 架构特点
|
||||
- 基于axios构建,支持请求/响应转换
|
||||
@@ -113,4 +123,14 @@ knowai-core/
|
||||
|
||||
### 2025-11-11
|
||||
- 因服务器性能原因去除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,
|
||||
GetCommentsResponse,
|
||||
LikeCommentRequest,
|
||||
LikeCommentResponse
|
||||
LikeCommentResponse,
|
||||
GetHotPostsRequest,
|
||||
GetHotPostsResponse,
|
||||
GetPostRankingRequest,
|
||||
GetPostRankingResponse
|
||||
} from '@/types/post/api';
|
||||
|
||||
// 帖子API服务工厂函数
|
||||
@@ -61,5 +65,15 @@ export const postApi = (client: ApiClient) => ({
|
||||
// 点赞评论
|
||||
likeComment: ({ commentId }: LikeCommentRequest): Promise<LikeCommentResponse> => {
|
||||
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,
|
||||
UserProfileUpdateResponse,
|
||||
UserFollowRequest,
|
||||
UserFollowResponse
|
||||
UserFollowResponse,
|
||||
GetHotAuthorsRequest,
|
||||
GetHotAuthorsResponse,
|
||||
GetAuthorRankingRequest,
|
||||
GetAuthorRankingResponse
|
||||
} from '@/types/user';
|
||||
|
||||
// 用户API服务工厂函数
|
||||
@@ -47,5 +51,15 @@ export const userApi = (client: ApiClient) => ({
|
||||
// 取消关注用户
|
||||
unfollowUser: ({ userId }: UserFollowRequest): Promise<UserFollowResponse> => {
|
||||
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;
|
||||
// 如果成功获取用户信息,触发session_authenticated事件
|
||||
authEventManager.emit('session_authenticated', this.currentUser);
|
||||
return this.currentUser;
|
||||
return response.user;
|
||||
} catch (error) {
|
||||
this.currentUser = null;
|
||||
// 如果获取用户信息失败,触发session_expired事件
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# Types 模块
|
||||
|
||||
## 架构设计
|
||||
|
||||
Types模块用于定义前端数据模型,提供给其他模块进行API或行为封装。
|
||||
|
||||
## 包含
|
||||
|
||||
1. **chat**
|
||||
- 包
|
||||
@@ -111,6 +111,33 @@ export interface LikeCommentResponse {
|
||||
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 {
|
||||
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 './search';
|
||||
export * from './enum';
|
||||
export * from './api';
|
||||
@@ -1,5 +1,6 @@
|
||||
// 导出所有工具函数
|
||||
export * from './date';
|
||||
export * from './string';
|
||||
export * from './number';
|
||||
export * from './data';
|
||||
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