feat(content): add rich content rendering with @mentions and vote segments
Some checks failed
Frontend CI / build-and-push-web (push) Failing after 8m30s
Frontend CI / ota-android (push) Successful in 10m43s
Frontend CI / build-android-apk (push) Successful in 1h24m38s

- 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:
lafay
2026-04-23 22:29:58 +08:00
parent eb4e1c080d
commit b2c3d5e54e
23 changed files with 797 additions and 127 deletions

View File

@@ -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;
}