- Introduced a new service for managing notification preferences, including push notifications, sound, and vibration settings. - Updated the notification handling logic to respect user preferences, ensuring notifications are displayed according to user settings. - Refactored the App and various screens to integrate the new notification preferences, improving user experience and consistency. - Enhanced the HomeScreen and NotificationSettingsScreen to load and update notification settings seamlessly. - Implemented a mechanism to hide the bottom tab bar based on scroll events, improving navigation usability.
290 lines
7.3 KiB
TypeScript
290 lines
7.3 KiB
TypeScript
/**
|
|
* Post Entity - 帖子领域实体
|
|
* 定义帖子的核心属性和行为,不依赖任何外部框架
|
|
*/
|
|
|
|
// ==================== 帖子状态枚举 ====================
|
|
|
|
export type PostStatus = 'published' | 'draft' | 'deleted';
|
|
|
|
// ==================== 值对象 ====================
|
|
|
|
/**
|
|
* 帖子作者信息
|
|
*/
|
|
export interface PostAuthor {
|
|
id: string;
|
|
username: string;
|
|
nickname?: string;
|
|
avatar?: string;
|
|
is_following?: boolean;
|
|
is_following_me?: boolean;
|
|
}
|
|
|
|
/**
|
|
* 帖子图片信息
|
|
*/
|
|
export interface PostImage {
|
|
url: string;
|
|
width?: number;
|
|
height?: number;
|
|
thumbnailUrl?: string;
|
|
}
|
|
|
|
/**
|
|
* 帖子标签
|
|
*/
|
|
export interface PostTag {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
|
|
// ==================== 主实体 ====================
|
|
|
|
/**
|
|
* 帖子实体
|
|
*/
|
|
export interface Post {
|
|
/** 帖子唯一标识 */
|
|
id: string;
|
|
/** 作者ID */
|
|
authorId: string;
|
|
/** 作者信息 */
|
|
author?: PostAuthor;
|
|
/** 帖子标题 */
|
|
title: string;
|
|
/** 帖子内容 */
|
|
content: string;
|
|
/** 图片列表 */
|
|
images: PostImage[];
|
|
/** 点赞数 (camelCase) */
|
|
likesCount: number;
|
|
/** 评论数 (camelCase) */
|
|
commentsCount: number;
|
|
/** 分享数 (camelCase) */
|
|
sharesCount: number;
|
|
/** 浏览数 (camelCase) */
|
|
viewsCount: number;
|
|
/** 收藏数 (camelCase) */
|
|
favoritesCount: number;
|
|
/** 当前用户是否已点赞 (camelCase) */
|
|
isLiked: boolean;
|
|
/** 当前用户是否已收藏 (camelCase) */
|
|
isFavorited: boolean;
|
|
/** 是否置顶 (camelCase) */
|
|
isPinned: boolean;
|
|
/** 帖子状态 */
|
|
status: PostStatus;
|
|
/** 所属频道ID */
|
|
channelId?: string;
|
|
/** 频道摘要(列表 API 填充,供 PostCard 等展示) */
|
|
channel?: { id: string; name: string } | null;
|
|
/** 标签列表 */
|
|
tags: string[];
|
|
/** 创建时间 */
|
|
createdAt: string;
|
|
/** 更新时间 */
|
|
updatedAt: string;
|
|
/** 用户编辑内容的时间(与统计类更新解耦) */
|
|
contentEditedAt?: string;
|
|
|
|
// ==================== 向后兼容字段 (snake_case) ====================
|
|
// 这些字段用于与旧代码兼容,新代码应使用 camelCase 版本
|
|
|
|
/** @deprecated 请使用 likesCount */
|
|
likes_count?: number;
|
|
/** @deprecated 请使用 commentsCount */
|
|
comments_count?: number;
|
|
/** @deprecated 请使用 favoritesCount */
|
|
favorites_count?: number;
|
|
/** @deprecated 请使用 sharesCount */
|
|
shares_count?: number;
|
|
/** @deprecated 请使用 viewsCount */
|
|
views_count?: number;
|
|
/** @deprecated 请使用 isLiked */
|
|
is_liked?: boolean;
|
|
/** @deprecated 请使用 isFavorited */
|
|
is_favorited?: boolean;
|
|
/** @deprecated 请使用 isPinned */
|
|
is_pinned?: boolean;
|
|
/** @deprecated 请使用 authorId */
|
|
user_id?: string;
|
|
/** @deprecated 请使用 createdAt */
|
|
created_at?: string;
|
|
/** @deprecated 请使用 updatedAt */
|
|
updated_at?: string;
|
|
/** @deprecated 请使用 contentEditedAt */
|
|
content_edited_at?: string;
|
|
/** @deprecated 请使用 channelId */
|
|
channel_id?: string;
|
|
/** @deprecated 请使用 status */
|
|
status_str?: string;
|
|
/** 投票帖子标识 (部分旧代码使用) */
|
|
is_vote?: boolean;
|
|
/** 锁定状态 (部分旧代码使用) */
|
|
is_locked?: boolean;
|
|
/** 置顶评论 (部分旧代码使用) */
|
|
top_comment?: any;
|
|
}
|
|
|
|
// ==================== 工厂函数 ====================
|
|
|
|
/**
|
|
* 创建帖子作者信息
|
|
*/
|
|
export const createPostAuthor = (data: Partial<PostAuthor>): PostAuthor => ({
|
|
id: data.id || '',
|
|
username: data.username || '',
|
|
nickname: data.nickname,
|
|
avatar: data.avatar,
|
|
is_following: data.is_following,
|
|
is_following_me: data.is_following_me,
|
|
});
|
|
|
|
/**
|
|
* 创建帖子图片信息
|
|
*/
|
|
export const createPostImage = (data: Partial<PostImage>): PostImage => ({
|
|
url: data.url || '',
|
|
width: data.width,
|
|
height: data.height,
|
|
thumbnailUrl: data.thumbnailUrl,
|
|
});
|
|
|
|
/**
|
|
* 创建帖子实体
|
|
*/
|
|
export const createPost = (data: Partial<Post>): Post => ({
|
|
id: data.id || '',
|
|
authorId: data.authorId || '',
|
|
author: data.author,
|
|
title: data.title || '',
|
|
content: data.content || '',
|
|
images: data.images || [],
|
|
likesCount: data.likesCount || 0,
|
|
commentsCount: data.commentsCount || 0,
|
|
sharesCount: data.sharesCount || 0,
|
|
viewsCount: data.viewsCount || 0,
|
|
favoritesCount: data.favoritesCount || 0,
|
|
isLiked: data.isLiked || false,
|
|
isFavorited: data.isFavorited || false,
|
|
isPinned: data.isPinned || false,
|
|
status: data.status || 'published',
|
|
channelId: data.channelId,
|
|
tags: data.tags || [],
|
|
createdAt: data.createdAt || new Date().toISOString(),
|
|
updatedAt: data.updatedAt || new Date().toISOString(),
|
|
});
|
|
|
|
// ==================== 类型守卫 ====================
|
|
|
|
/**
|
|
* 检查是否为有效的帖子状态
|
|
*/
|
|
export const isValidPostStatus = (status: string): status is PostStatus => {
|
|
return ['published', 'draft', 'deleted'].includes(status);
|
|
};
|
|
|
|
/**
|
|
* 检查帖子是否已发布
|
|
*/
|
|
export const isPostPublished = (post: Post): boolean => {
|
|
return post.status === 'published';
|
|
};
|
|
|
|
/**
|
|
* 检查帖子是否已删除
|
|
*/
|
|
export const isPostDeleted = (post: Post): boolean => {
|
|
return post.status === 'deleted';
|
|
};
|
|
|
|
/**
|
|
* 检查帖子是否为草稿
|
|
*/
|
|
export const isPostDraft = (post: Post): boolean => {
|
|
return post.status === 'draft';
|
|
};
|
|
|
|
// ==================== 辅助函数 ====================
|
|
|
|
/**
|
|
* 检查当前用户是否为帖子作者
|
|
*/
|
|
export const isPostAuthor = (post: Post, userId: string): boolean => {
|
|
return post.authorId === userId;
|
|
};
|
|
|
|
/**
|
|
* 获取帖子的主要图片(第一张图片)
|
|
*/
|
|
export const getPostThumbnail = (post: Post): PostImage | undefined => {
|
|
return post.images[0];
|
|
};
|
|
|
|
/**
|
|
* 检查帖子是否包含图片
|
|
*/
|
|
export const hasPostImages = (post: Post): boolean => {
|
|
return post.images.length > 0;
|
|
};
|
|
|
|
/**
|
|
* 获取帖子的显示标题(优先使用标题,否则使用内容摘要)
|
|
*/
|
|
export const getPostDisplayTitle = (post: Post, maxLength: number = 50): string => {
|
|
if (post.title) {
|
|
return post.title;
|
|
}
|
|
if (post.content.length > maxLength) {
|
|
return post.content.substring(0, maxLength) + '...';
|
|
}
|
|
return post.content;
|
|
};
|
|
|
|
/**
|
|
* 计算帖子的互动总数
|
|
*/
|
|
export const getPostTotalEngagement = (post: Post): number => {
|
|
return post.likesCount + post.commentsCount + post.sharesCount + post.favoritesCount;
|
|
};
|
|
|
|
/**
|
|
* 根据创建时间 ISO 字符串格式化为列表用相对时间(与历史 formatPostTime 行为一致)
|
|
*/
|
|
export const formatPostCreatedAtString = (createdAt: string | undefined | null): string => {
|
|
if (!createdAt) return '';
|
|
const createdAtDate = new Date(createdAt);
|
|
if (Number.isNaN(createdAtDate.getTime())) return '';
|
|
|
|
const now = new Date();
|
|
const diffMs = now.getTime() - createdAtDate.getTime();
|
|
if (diffMs < 0) {
|
|
return createdAtDate.toLocaleDateString('zh-CN');
|
|
}
|
|
const diffSeconds = Math.floor(diffMs / 1000);
|
|
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
const diffHours = Math.floor(diffMinutes / 60);
|
|
const diffDays = Math.floor(diffHours / 24);
|
|
|
|
if (diffSeconds < 60) {
|
|
return '刚刚';
|
|
}
|
|
if (diffMinutes < 60) {
|
|
return `${diffMinutes}分钟前`;
|
|
}
|
|
if (diffHours < 24) {
|
|
return `${diffHours}小时前`;
|
|
}
|
|
if (diffDays < 7) {
|
|
return `${diffDays}天前`;
|
|
}
|
|
return createdAtDate.toLocaleDateString('zh-CN');
|
|
};
|
|
|
|
/**
|
|
* 格式化帖子创建时间为相对时间描述
|
|
*/
|
|
export const formatPostTime = (post: Post): string => {
|
|
return formatPostCreatedAtString(post.createdAt);
|
|
}; |