feat(content): add rich content rendering with @mentions and vote segments
- Add PostContentRenderer component for rendering posts/comments with segments - Add PostMentionInput component for @mention support in post/comment creation - Add VoteSegmentData and vote segment type for unified post creation API - Update post and comment services to support segments in API requests - Fix auth service to clear tokens before login/register - Improve database initialization with proper close/retry logic - Add verification check before allowing post creation - Add metro web shims for react-native-webrtc full package and requireNativeComponent - Update build config with git hash based version numbers
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { api, PaginatedData } from '../core/api';
|
||||
import { Comment, CreateCommentInput } from '@/types';
|
||||
import { Comment, CreateCommentInput, MessageSegment } from '@/types';
|
||||
import { CursorPaginationRequest, CursorPaginationResponse, CommentDTO } from '@/types/dto';
|
||||
|
||||
// 评论列表响应
|
||||
@@ -23,8 +23,9 @@ type CommentResponse = Comment;
|
||||
interface CreateCommentRequest {
|
||||
postId: string;
|
||||
content: string;
|
||||
segments?: MessageSegment[];
|
||||
parentId?: string;
|
||||
images?: string[]; // 图片URL列表
|
||||
images?: string[];
|
||||
replyToUserId?: string;
|
||||
}
|
||||
|
||||
@@ -130,12 +131,14 @@ class CommentService {
|
||||
content: data.content,
|
||||
};
|
||||
|
||||
// 如果有父评论ID,才添加 parent_id 字段
|
||||
if (data.segments && data.segments.length > 0) {
|
||||
requestBody.segments = data.segments;
|
||||
}
|
||||
|
||||
if (data.parentId) {
|
||||
requestBody.parent_id = data.parentId;
|
||||
}
|
||||
|
||||
// 如果有图片,添加 images 字段
|
||||
if (data.images && data.images.length > 0) {
|
||||
requestBody.images = data.images;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { api, PaginatedData } from '../core/api';
|
||||
import { Post, CreatePostInput } from '@/types';
|
||||
import { CursorPaginationRequest, CursorPaginationResponse } from '@/types/dto';
|
||||
import { CursorPaginationRequest, CursorPaginationResponse, MessageSegment } from '@/types/dto';
|
||||
|
||||
// 帖子列表响应
|
||||
interface PostListResponse {
|
||||
@@ -22,7 +22,8 @@ type PostResponse = Post;
|
||||
// 创建帖子请求
|
||||
interface CreatePostRequest {
|
||||
title: string;
|
||||
content: string;
|
||||
content?: string;
|
||||
segments?: MessageSegment[];
|
||||
images?: string[];
|
||||
channel_id?: string;
|
||||
}
|
||||
@@ -31,6 +32,7 @@ interface CreatePostRequest {
|
||||
interface UpdatePostRequest {
|
||||
title?: string;
|
||||
content?: string;
|
||||
segments?: MessageSegment[];
|
||||
images?: string[];
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { api } from '../core/api';
|
||||
import { Post, VoteResultDTO, CreateVotePostRequest } from '@/types';
|
||||
import { Post, VoteResultDTO, CreateVotePostRequest, MessageSegment } from '@/types';
|
||||
|
||||
// 投票响应
|
||||
interface VoteResponse {
|
||||
@@ -23,12 +23,9 @@ interface UpdateVoteOptionResponse {
|
||||
*/
|
||||
class VoteService {
|
||||
/**
|
||||
* 创建投票帖子
|
||||
* @param data 创建投票帖子请求数据
|
||||
* @returns 创建的帖子或null
|
||||
* 创建投票帖子(通过统一的 POST /posts 接口,投票选项作为 vote segment)
|
||||
*/
|
||||
async createVotePost(data: CreateVotePostRequest): Promise<Post | null> {
|
||||
// 验证投票选项数量
|
||||
if (!data.vote_options || data.vote_options.length < 2) {
|
||||
console.error('[VoteService] 投票选项至少需要2个');
|
||||
return null;
|
||||
@@ -38,7 +35,30 @@ class VoteService {
|
||||
return null;
|
||||
}
|
||||
|
||||
const response = await api.post<Post>('/posts/vote', data);
|
||||
// 构建 segments:先放文本内容,再放投票 segment
|
||||
const segments: MessageSegment[] = [];
|
||||
if (data.content) {
|
||||
segments.push({ type: 'text', data: { text: data.content } });
|
||||
}
|
||||
segments.push({
|
||||
type: 'vote',
|
||||
data: {
|
||||
options: data.vote_options.map((opt, i) => ({
|
||||
id: `opt_${i + 1}`,
|
||||
content: typeof opt === 'string' ? opt : opt.content,
|
||||
})),
|
||||
max_choices: 1,
|
||||
is_multi_choice: false,
|
||||
},
|
||||
});
|
||||
|
||||
const response = await api.post<Post>('/posts', {
|
||||
title: data.title,
|
||||
content: data.content || '',
|
||||
segments,
|
||||
images: data.images,
|
||||
channel_id: data.channel_id,
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user