import { tt } from '@/utils/i18nfun.uts' // 获取语言本地化 key(如 mt.language.zh-CN),用于 $t() export const getLanguageDisplayNameKey = (code: string): string => { if (code === 'zh-CN') return 'mt.language.zh-CN' if (code === 'zh-TW') return 'mt.language.zh-TW' if (code === 'en-US') return 'mt.language.en-US' if (code === 'ja-JP') return 'mt.language.ja-JP' if (code === 'ko-KR') return 'mt.language.ko-KR' if (code === 'fr-FR') return 'mt.language.fr-FR' if (code === 'de-DE') return 'mt.language.de-DE' if (code === 'es-ES') return 'mt.language.es-ES' return code } // 基础数据类型 - 全部使用强类型定义,便于类型推断和类型安全 export type InfoContent = { id: string title?: string summary?: string | null content?: string author?: string trans_data?:TranslationData published_at?: string quality_score: number view_count?: number like_count?: number share_count?: number category_id?: string category_name?: CategoryTranslation category_name_text?: string // 兼容性字段,用于简单的字符串显示 original_language?: string source_url?: string | null tags?: string[] | null created_at?: string updated_at?: string is_liked?: boolean loading?: boolean // UI状态字段,用于加载状态显示 // 扩展字段 - 支持视频、音频和图集模式 raw_content_id?: string | null keywords?: string[] | null entities?: any | null // jsonb sentiment_score?: number | null readability_score?: number | null credibility_score?: number | null comment_count?: number | null featured_until?: string | null status?: string | null ai_processed_at?: string | null favorite_count?: number | null is_featured?: boolean | null content_type?: string | null // 视频相关字段 video_url?: string | null video_duration?: number | null video_poster?: string | null video_width?: number | null video_height?: number | null video_size?: number | null video_format?: string | null video_quality?: string | null // 音频相关字段 audio_url?: string | null audio_duration?: number | null audio_size?: number | null audio_format?: string | null audio_bitrate?: number | null audio_sample_rate?: number | null audio_cover?: string | null // 图片相关字段 image_url?: string | null image_width?: number | null image_height?: number | null image_size?: number | null image_format?: string | null image_quality?: string | null image_alt_text?: string | null images?: any | null // jsonb - 图集模式 // 多媒体设置 allow_danmu?: boolean | null allow_download?: boolean | null media_metadata?: any | null // jsonb // 序列号字段 cid?: number | null } export type TranslationData = { id: string content_id: string language_id: string title: string content: string summary: string | null human_verified: boolean created_at: string updated_at: string } // 新增:CategoryTranslation 类型 export type CategoryTranslation = { name: string } // 新增:CategoryData 类型,严格对应 Supabase 返回结构 export type CategoryData = { id: string name_key: string parent_id: string | null level?: number ai_keywords?: string[] confidence_threshold?: number sort_order?: number is_active?: boolean created_at?: string updated_at?: string translations?: CategoryTranslation[] } // 新增专题相关类型 export type TopicData = { id: string title: string description: string created_by: string is_active: boolean content_count: number created_at: string updated_at: string } export type TopicContentData = { id: string topic_id: string content_id: string display_order: number created_at: string updated_at: string is_liked?:boolean } export type TopicTimelineData = { id: string topic_id: string event: string event_time: string created_at: string updated_at: string } // 评论系统相关类型 export type CommentData = { id: string content_id: string user_id: string user_name: string content: string like_count: number reply_count: number status: string created_at: string updated_at: string is_liked?: boolean level?: number // 多级评论层级,0为主评论,1为一级回复,依此类推 is_author?: boolean // 是否为当前用户本人评论 } export type CommentReplyData = { id: string comment_id: string user_id: string user_name: string content: string created_at: string updated_at: string is_liked?:boolean } export type CommentReactionData = { id: string comment_id: string user_id: string reaction_type: string created_at: string is_liked?:boolean } export type UserBehaviorData = { id: string user_id: string content_id: string behavior_type: string behavior_data: any duration_seconds: number | null scroll_percentage: number | null device_type: string source: string session_id: string ip_address: string user_agent: string created_at: string } export type RecommendationData = { id: string user_id: string content_id: string algorithm_type: string score: number reason: string position: number shown_at: string clicked_at: string feedback_score: number feedback_reason: string created_at: string } export type ChatSessionData = { id: string user_id: string session_name: string language: string context: any ai_model: string total_messages: number total_tokens: number cost_usd: number last_message_at: string is_active: boolean created_at: string updated_at: string } export type ChatMessageData = { id: string session_id: string message_type: string content: string intent?: string attachments?: any ai_provider?: string tokens_used?: number processing_time_ms?: number cost_usd?: number feedback_score?: number feedback_reason?: string created_at?: string } export type LanguageData = { id: string code: string name: string native_name: string is_active: boolean } export type UserSettingsData = { id: string user_id: string preferred_languages: string[] preferred_categories: string[] reading_mode: string font_size: string auto_translate: boolean notification_enabled: boolean created_at: string updated_at: string } export type SearchHistoryData = { id: string user_id: string keyword: string searched_at: string } // 已合并到 TranslationData,避免重复定义 // export type Translation = TranslationData export type Topic = { id: string title: string description: string topic_type?: string status?: string cover_image?: string created_by?: string is_active?: boolean content_count?: number view_count?: number created_at?: string updated_at?: string } export type Comment = { id: string content_id: string user_id: string user_name: string content: string like_count: number reply_count: number created_at: string updated_at: string } export type Language = { id: string code: string name: string native_name: string is_active: boolean } // 状态和UI类型 - 与template交互的变量使用1维变量 export type PageState = { loading: boolean error: string | null currentPage: number pageSize: number total: number } export type StatsData = { total_contents: number published_contents: number trending_contents: number avg_quality_score: string } export type ResponsiveState = { isLargeScreen: boolean isSmallScreen: boolean screenWidth: number cardColumns: number } // 选择器选项类型 - UTS Android支持的简单类型 export type PickerOption = { value: string text: string } export type SortOption = { column: string ascending: boolean } // 表单数据类型 - 避免复杂嵌套,使用简单类型 export type ContentFormData = { title: string content: string summary: string category_id: string tags: string // 改为字符串,用逗号分隔 source_url: string author: string content_type?: string // 视频相关字段 video_url?: string video_duration?: number video_poster?: string video_width?: number video_height?: number video_quality?: string // 音频相关字段 audio_url?: string audio_duration?: number audio_cover?: string audio_format?: string // 图片相关字段 image_url?: string image_alt_text?: string images?: string // JSON字符串存储图集数据 // 多媒体设置 allow_danmu?: boolean allow_download?: boolean } export type TranslationFormData = { content_id: string language_id: string title: string content: string summary: string } // 筛选器类型 - 使用简单字符串类型 export type ContentFilterData = { category_id: string | null language: string | null status: string quality_min: string | null date_from: string | null date_to: string | null search_text: string | null date_range?: string | null content_type?: string | null // 新增:按内容类型筛选 is_featured?: boolean | null // 新增:是否精选 has_video?: boolean | null // 新增:是否包含视频 has_audio?: boolean | null // 新增:是否包含音频 has_images?: boolean | null // 新增:是否包含图片 } // 聊天相关类型 export type ChatState = { isTyping: boolean currentSession: string |null messageCount: number } // 用户偏好类型 - 使用字符串存储数组数据 export type UserPreferences = { preferred_languages: string // JSON字符串存储数组 preferred_categories: string // JSON字符串存储数组 reading_mode: string // 'light', 'dark', 'auto' font_size: string // 'small', 'medium', 'large' auto_translate: boolean notification_enabled: boolean } // 常量定义 - 内容状态 export const CONTENT_STATUS = { DRAFT: 'draft', PUBLISHED: 'published', ARCHIVED: 'archived', DELETED: 'deleted' } // 内容类型常量 - 支持多媒体 export const CONTENT_TYPES = { TEXT: 'text', // 纯文本 IMAGE: 'image', // 图片 VIDEO: 'video', // 视频 AUDIO: 'audio', // 音频 GALLERY: 'gallery', // 图集 MIXED: 'mixed' // 混合内容 } // 通用选项类型(用于 value/text 结构的所有 option) export type OptionItem = { value: string text: string } // 视频质量选项 export const VIDEO_QUALITY_OPTIONS: Array = [ { value: '4K', text: 'mt.video.quality.4k' }, { value: '1080P', text: 'mt.video.quality.1080p' }, { value: '720P', text: 'mt.video.quality.720p' }, { value: '480P', text: 'mt.video.quality.480p' }, { value: '360P', text: 'mt.video.quality.360p' } ] // 音频格式选项 export const AUDIO_FORMAT_OPTIONS: Array = [ { value: 'mp3', text: 'mt.audio.format.mp3' }, { value: 'wav', text: 'mt.audio.format.wav' }, { value: 'flac', text: 'mt.audio.format.flac' }, { value: 'aac', text: 'mt.audio.format.aac' }, { value: 'm4a', text: 'mt.audio.format.m4a' } ] // 行为类型常量 export const BEHAVIOR_TYPES = { VIEW: 'view', LIKE: 'like', SHARE: 'share', COMMENT: 'comment', SAVE: 'save', CLICK: 'click' } // 消息类型常量 export const MESSAGE_TYPES = { USER: 'user', ASSISTANT: 'assistant', SYSTEM: 'system' } // 专题类型常量 export const TOPIC_TYPES: Array = [ { value: 'breaking', text: 'mt.topicType.breaking' }, { value: 'trending', text: 'mt.topicType.trending' }, { value: 'series', text: 'mt.topicType.series' }, { value: 'analysis', text: 'mt.topicType.analysis' }, { value: 'guide', text: 'mt.topicType.guide' }, { value: 'interview', text: 'mt.topicType.interview' }, { value: 'report', text: 'mt.topicType.report' }, { value: 'timeline', text: 'mt.topicType.timeline' } ] // 专题状态常量 export const TOPIC_STATUS = { DRAFT: 'draft', ACTIVE: 'active', FEATURED: 'featured', ARCHIVED: 'archived', CLOSED: 'closed' } // 评论状态常量 export const COMMENT_STATUS = { ACTIVE: 'active', HIDDEN: 'hidden', DELETED: 'deleted', PENDING_REVIEW: 'pending_review', REJECTED: 'rejected' } // 评论类型常量 export const COMMENT_TYPES = { CONTENT: 'content', // 内容评论 TOPIC: 'topic', // 专题评论 REPLY: 'reply' // 回复评论 } // 评论排序选项 export const COMMENT_SORT_OPTIONS: Array = [ { value: 'created_at_desc', text: 'mt.comment.sort.latest' }, { value: 'created_at_asc', text: 'mt.comment.sort.earliest' }, { value: 'like_count_desc', text: 'mt.comment.sort.mostLiked' }, { value: 'reply_count_desc', text: 'mt.comment.sort.mostReplied' } ] // 评论举报类型 export const COMMENT_REPORT_TYPES: Array = [ { value: 'spam', text: 'mt.comment.report.spam' }, { value: 'inappropriate', text: 'mt.comment.report.inappropriate' }, { value: 'harassment', text: 'mt.comment.report.harassment' }, { value: 'misinformation', text: 'mt.comment.report.misinformation' }, { value: 'copyright', text: 'mt.comment.report.copyright' }, { value: 'other', text: 'mt.comment.report.other' } ] // 语言选项常量 export const LANGUAGE_OPTIONS: Array = [ { id: 'zh-CN', code: 'zh-CN', name: 'mt.language.zh-CN', native_name: 'mt.language.zh-CN', is_active: true }, { id: 'zh-TW', code: 'zh-TW', name: 'mt.language.zh-TW', native_name: 'mt.language.zh-TW', is_active: true }, { id: 'en-US', code: 'en-US', name: 'mt.language.en-US', native_name: 'mt.language.en-US', is_active: true }, { id: 'ja-JP', code: 'ja-JP', name: 'mt.language.ja-JP', native_name: 'mt.language.ja-JP', is_active: true }, { id: 'ko-KR', code: 'ko-KR', name: 'mt.language.ko-KR', native_name: 'mt.language.ko-KR', is_active: true }, { id: 'fr-FR', code: 'fr-FR', name: 'mt.language.fr-FR', native_name: 'mt.language.fr-FR', is_active: true }, { id: 'de-DE', code: 'de-DE', name: 'mt.language.de-DE', native_name: 'mt.language.de-DE', is_active: true }, { id: 'es-ES', code: 'es-ES', name: 'mt.language.es-ES', native_name: 'mt.language.es-ES', is_active: true } ] export const SORT_OPTIONS: Array = [ { value: 'published_at_desc', text: 'mt.sort.latest' }, { value: 'published_at_asc', text: 'mt.sort.earliest' }, { value: 'quality_score_desc', text: 'mt.sort.highestScore' }, { value: 'view_count_desc', text: 'mt.sort.mostViewed' }, { value: 'like_count_desc', text: 'mt.sort.mostLiked' }, { value: 'share_count_desc', text: 'mt.sort.mostShared' } ] export const getCommentStatusTextKey = (status: string): string => { console.log(status,COMMENT_STATUS.HIDDEN) if (status === COMMENT_STATUS["ACTIVE"]) return 'mt.comment.status.active' if (status === COMMENT_STATUS.HIDDEN) return 'mt.comment.status.hidden' if (status === COMMENT_STATUS.DELETED) return 'mt.comment.status.deleted' if (status === COMMENT_STATUS.PENDING_REVIEW) return 'mt.comment.status.pending' if (status === COMMENT_STATUS.REJECTED) return 'mt.comment.status.rejected' return 'mt.comment.status.unknown' } // 格式化相对时间,返回 i18n key export const formatRelativeTimeKey = (dateString: string | null): string => { if (dateString == null || dateString === '') return '' const now = new Date() const date = new Date(dateString) const diff = now.getTime() - date.getTime() const seconds = Math.floor(diff / 1000) const minutes = Math.floor(seconds / 60) const hours = Math.floor(minutes / 60) const days = Math.floor(hours / 24) if (days > 0) return days + tt('mt.time.daysAgo') if (hours > 0) return hours + tt('mt.time.hoursAgo') if (minutes > 0) return minutes + tt('mt.time.minutesAgo') return tt('mt.time.justNow') } // 语言显示名称,返回本地化字符串 export const getLanguageDisplayName = (code: string): string => { const map = { 'zh-CN': 'mt.language.zh-CN', 'zh-TW': 'mt.language.zh-TW', 'en-US': 'mt.language.en-US', 'ja-JP': 'mt.language.ja-JP', 'ko-KR': 'mt.language.ko-KR', 'fr-FR': 'mt.language.fr-FR', 'de-DE': 'mt.language.de-DE', 'es-ES': 'mt.language.es-ES' } const key = map[code] ?? code return tt(key) } // 质量分数对应颜色,返回颜色字符串(如需 className 可调整) export const getQualityScoreColor = (score: number): string => { if (score >= 90) return '#4CAF50' // excellent - green if (score >= 75) return '#8BC34A' // good - light green if (score >= 60) return '#FFC107' // normal - amber return '#F44336' // poor - red } // 质量分数对应文本,返回 i18n key export const getQualityScoreText = (score: number): string => { if (score >= 90) return tt('mt.quality.excellent') if (score >= 75) return tt('mt.quality.good') if (score >= 60) return tt('mt.quality.normal') return tt('mt.quality.poor') } // 专题类型显示名称,返回本地化字符串 export const getTopicTypeDisplayName = (typeCode: string): string => { const typeItem = TOPIC_TYPES.find(item => item.value === typeCode); return typeItem != null ? tt(typeItem.text) : typeCode; }; // 专题状态对应颜色,返回颜色字符串 export const getTopicStatusColor = (status: string): string => { if (status === TOPIC_STATUS.FEATURED) return '#FF6B35' // featured - orange if (status === TOPIC_STATUS.ACTIVE) return '#4CAF50' // active - green if (status === TOPIC_STATUS.DRAFT) return '#9E9E9E' // draft - gray if (status === TOPIC_STATUS.ARCHIVED) return '#607D8B' // archived - blue gray if (status === TOPIC_STATUS.CLOSED) return '#F44336' // closed - red return '#9E9E9E' // default - gray } // 获取内容类型显示名称,返回本地化字符串 export const getContentTypeDisplayName = (contentType: string | null): string => { if (contentType === CONTENT_TYPES.TEXT) return tt('mt.content.type.text') if (contentType === CONTENT_TYPES.IMAGE) return tt('mt.content.type.image') if (contentType === CONTENT_TYPES.VIDEO) return tt('mt.content.type.video') if (contentType === CONTENT_TYPES.AUDIO) return tt('mt.content.type.audio') if (contentType === CONTENT_TYPES.GALLERY) return tt('mt.content.type.gallery') if (contentType === CONTENT_TYPES.MIXED) return tt('mt.content.type.mixed') return tt('mt.content.type.text') // 默认为文本 } // 获取内容类型对应图标 export const getContentTypeIcon = (contentType: string | null): string => { if (contentType === CONTENT_TYPES.TEXT) return 'text-outline' if (contentType === CONTENT_TYPES.IMAGE) return 'image-outline' if (contentType === CONTENT_TYPES.VIDEO) return 'videocam-outline' if (contentType === CONTENT_TYPES.AUDIO) return 'volume-high-outline' if (contentType === CONTENT_TYPES.GALLERY) return 'images-outline' if (contentType === CONTENT_TYPES.MIXED) return 'layers-outline' return 'text-outline' // 默认图标 } // 格式化文件大小 export const formatFileSize = (bytes: number | null): string => { if (bytes == null || bytes === 0) return '0 B' const k = 1024 const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] } // 格式化时长(秒转为 mm:ss 或 hh:mm:ss) export const formatDuration = (seconds: number | null): string => { if (seconds == null || seconds === 0) return '00:00' const hours = Math.floor(seconds / 3600) const minutes = Math.floor((seconds % 3600) / 60) const remainingSeconds = Math.floor(seconds % 60) if (hours > 0) { return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}` } else { return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}` } } // 检查内容是否有多媒体 export const hasMultimedia = (content: InfoContent): boolean => { return !!(content.video_url || content.audio_url || content.image_url || (content.images && content.images !== null)) } // 获取主要媒体类型 export const getPrimaryMediaType = (content: InfoContent): string => { if (content.video_url) return CONTENT_TYPES.VIDEO if (content.audio_url) return CONTENT_TYPES.AUDIO if (content.images && content.images !== null) return CONTENT_TYPES.GALLERY if (content.image_url) return CONTENT_TYPES.IMAGE return CONTENT_TYPES.TEXT }