import { Injectable } from '@angular/core'; import { FmodeParse, FmodeObject, FmodeQuery } from 'fmode-ng/core'; @Injectable({ providedIn: 'root' }) export class InfluencerDbService { private Parse: any; constructor() { // 使用已初始化的 Parse 实例 this.Parse = FmodeParse.with("nova"); } /** * 保存或更新红人信息到数据库 * @param influencerData 红人数据 */ async saveInfluencer(influencerData: any): Promise { try { // 查询是否已存在(根据 platform + unique_id) const query = new this.Parse.Query("Influencers"); query.equalTo("platform", influencerData.platform); query.equalTo("unique_id", influencerData.unique_id); let influencer = await query.first(); if (!influencer) { // 创建新记录 influencer = new this.Parse.Object("Influencers"); } // 设置字段 influencer.set("platform", influencerData.platform); influencer.set("unique_id", influencerData.unique_id); influencer.set("sec_uid", influencerData.sec_uid); influencer.set("nickname", influencerData.nickname); influencer.set("avatar_url", influencerData.avatar_url); influencer.set("signature", influencerData.signature); influencer.set("verification_type", influencerData.verification_type || "none"); influencer.set("follower_count", influencerData.follower_count); influencer.set("following_count", influencerData.following_count); influencer.set("heart_count", influencerData.heart_count); influencer.set("video_count", influencerData.video_count); // 计算互动率 if (influencerData.follower_count > 0) { const engagementRate = (influencerData.heart_count / influencerData.follower_count * 100).toFixed(2); influencer.set("engagement_rate", parseFloat(engagementRate)); } influencer.set("tags", influencerData.tags || []); influencer.set("data_source", influencerData.data_source || "search"); influencer.set("is_archived", false); // 保存 const savedInfluencer = await influencer.save(); console.log('Influencer saved:', savedInfluencer.id); return savedInfluencer; } catch (error) { console.error('Error saving influencer:', error); throw error; } } /** * 批量保存红人信息 * @param influencersData 红人数据数组 */ async saveInfluencers(influencersData: any[]): Promise { const results = []; for (const data of influencersData) { try { const saved = await this.saveInfluencer(data); results.push(saved); } catch (error) { console.error('Error saving influencer:', data.unique_id, error); } } return results; } /** * 查询红人列表 * @param options 查询选项 */ async getInfluencers(options: { platform?: string; limit?: number; skip?: number; sortBy?: string; } = {}): Promise { try { const query = new this.Parse.Query("Influencers"); // 过滤条件 if (options.platform) { query.equalTo("platform", options.platform); } query.equalTo("is_archived", false); // 排序 if (options.sortBy === 'followers') { query.descending("follower_count"); } else if (options.sortBy === 'engagement') { query.descending("engagement_rate"); } else { query.descending("createdAt"); } // 分页 if (options.limit) { query.limit(options.limit); } if (options.skip) { query.skip(options.skip); } const results = await query.find(); return results; } catch (error) { console.error('Error fetching influencers:', error); throw error; } } /** * 根据 ID 获取红人详情 * @param influencerId 红人 ID */ async getInfluencerById(influencerId: string): Promise { try { const query = new this.Parse.Query("Influencers"); const influencer = await query.get(influencerId); return influencer; } catch (error) { console.error('Error fetching influencer:', error); throw error; } } /** * 保存红人作品 * @param influencerId 红人 ID * @param postsData 作品数据数组 */ async saveInfluencerPosts(influencerId: string, postsData: any[]): Promise { const results = []; for (const postData of postsData) { try { // 查询是否已存在 const query = new this.Parse.Query("InfluencerPosts"); query.equalTo("platform_post_id", postData.platform_post_id); let post = await query.first(); if (!post) { post = new this.Parse.Object("InfluencerPosts"); } // 设置字段 post.set("influencer_id", influencerId); post.set("platform_post_id", postData.platform_post_id); post.set("desc", postData.desc); post.set("cover_url", postData.cover_url); post.set("video_url", postData.video_url); post.set("duration", postData.duration); post.set("create_time", postData.create_time); post.set("play_count", postData.play_count); post.set("digg_count", postData.digg_count); post.set("comment_count", postData.comment_count); post.set("share_count", postData.share_count); post.set("collect_count", postData.collect_count || 0); // 计算互动率 if (postData.play_count > 0) { const engagementRate = ((postData.digg_count + postData.comment_count + postData.share_count) / postData.play_count * 100).toFixed(2); post.set("engagement_rate", parseFloat(engagementRate)); } post.set("ai_keywords", postData.ai_keywords || []); post.set("is_representative", postData.is_representative || false); const savedPost = await post.save(); results.push(savedPost); } catch (error) { console.error('Error saving post:', postData.platform_post_id, error); } } return results; } /** * 获取红人的作品列表 * @param influencerId 红人 ID */ async getInfluencerPosts(influencerId: string): Promise { try { const query = new this.Parse.Query("InfluencerPosts"); query.equalTo("influencer_id", influencerId); query.descending("create_time"); query.limit(20); const results = await query.find(); return results; } catch (error) { console.error('Error fetching posts:', error); throw error; } } /** * 保存作品评论 * @param postId 作品 ID * @param commentsData 评论数据数组 */ async savePostComments(postId: string, commentsData: any[]): Promise { const results = []; // 只保存前50条热门评论 const topComments = commentsData.slice(0, 50); for (const commentData of topComments) { try { // 查询是否已存在 const query = new this.Parse.Query("InfluencerPostComments"); query.equalTo("platform_comment_id", commentData.platform_comment_id); let comment = await query.first(); if (!comment) { comment = new this.Parse.Object("InfluencerPostComments"); } // 设置字段 comment.set("post_id", postId); comment.set("platform_comment_id", commentData.platform_comment_id); comment.set("user_id", commentData.user_id); comment.set("user_nickname", commentData.user_nickname); comment.set("user_avatar", commentData.user_avatar); comment.set("content", commentData.content); comment.set("digg_count", commentData.digg_count); comment.set("reply_count", commentData.reply_count); comment.set("create_time", commentData.create_time); comment.set("is_hot", commentData.digg_count > 100); // 点赞数超过100认为是热门评论 const savedComment = await comment.save(); results.push(savedComment); } catch (error) { console.error('Error saving comment:', commentData.platform_comment_id, error); } } return results; } /** * 保存搜索历史 * @param searchData 搜索数据 */ async saveSearchHistory(searchData: { user_id?: string; keyword: string; result_count: number; search_type: string; }): Promise { try { const searchHistory = new this.Parse.Object("InfluencerSearchHistory"); if (searchData.user_id) { searchHistory.set("user_id", searchData.user_id); } searchHistory.set("keyword", searchData.keyword); searchHistory.set("result_count", searchData.result_count); searchHistory.set("search_type", searchData.search_type); const saved = await searchHistory.save(); return saved; } catch (error) { console.error('Error saving search history:', error); // 不抛出错误,避免阻塞主流程 } } }