- 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
135 lines
3.4 KiB
TypeScript
135 lines
3.4 KiB
TypeScript
/**
|
||
* 投票服务
|
||
* 处理投票相关的API调用
|
||
*/
|
||
|
||
import { api } from '../core/api';
|
||
import { Post, VoteResultDTO, CreateVotePostRequest, MessageSegment } from '@/types';
|
||
|
||
// 投票响应
|
||
interface VoteResponse {
|
||
success: boolean;
|
||
message?: string;
|
||
}
|
||
|
||
// 更新投票选项响应
|
||
interface UpdateVoteOptionResponse {
|
||
success: boolean;
|
||
message?: string;
|
||
}
|
||
|
||
/**
|
||
* 投票服务类
|
||
*/
|
||
class VoteService {
|
||
/**
|
||
* 创建投票帖子(通过统一的 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;
|
||
}
|
||
if (data.vote_options.length > 10) {
|
||
console.error('[VoteService] 投票选项最多10个');
|
||
return null;
|
||
}
|
||
|
||
// 构建 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;
|
||
}
|
||
|
||
/**
|
||
* 获取投票结果
|
||
* @param postId 帖子ID
|
||
* @returns 投票结果或null
|
||
*/
|
||
async getVoteResult(postId: string): Promise<VoteResultDTO | null> {
|
||
try {
|
||
const response = await api.get<VoteResultDTO>(`/posts/${postId}/vote`);
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('[VoteService] 获取投票结果失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 投票
|
||
* @param postId 帖子ID
|
||
* @param optionId 选项ID
|
||
* @returns 是否成功
|
||
*/
|
||
async vote(postId: string, optionId: string): Promise<boolean> {
|
||
try {
|
||
const response = await api.post<VoteResponse>(`/posts/${postId}/vote`, {
|
||
option_id: optionId,
|
||
});
|
||
return response.data.success;
|
||
} catch (error) {
|
||
console.error('[VoteService] 投票失败:', error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 取消投票
|
||
* @param postId 帖子ID
|
||
* @returns 是否成功
|
||
*/
|
||
async unvote(postId: string): Promise<boolean> {
|
||
try {
|
||
const response = await api.delete<VoteResponse>(`/posts/${postId}/vote`);
|
||
return response.data.success;
|
||
} catch (error) {
|
||
console.error('[VoteService] 取消投票失败:', error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新投票选项(作者权限)
|
||
* @param optionId 选项ID
|
||
* @param content 新内容
|
||
* @param postId 帖子ID
|
||
* @returns 是否成功
|
||
*/
|
||
async updateVoteOption(optionId: string, content: string, postId: string): Promise<boolean> {
|
||
try {
|
||
const response = await api.put<UpdateVoteOptionResponse>(
|
||
`/posts/${postId}/vote/options/${optionId}`,
|
||
{ content }
|
||
);
|
||
return response.data.success;
|
||
} catch (error) {
|
||
console.error('[VoteService] 更新投票选项失败:', error);
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
export const voteService = new VoteService();
|