(() => { const scope = 'local-guest'; function seedIpOperatorScenario(scenario = 'ready') { const now = new Date().toISOString(); const user = { objectId: scope, username: 'ip-operator-e2e', displayName: 'IP Operator E2E', role: 'user', createdAt: now, }; clearIpOperatorData(); localStorage.setItem('videoWorkflow.authSession', JSON.stringify({ token: 'ip-operator-e2e-token', user })); localStorage.setItem('tiktok.currentTab', 'ip-operator'); sessionStorage.clear(); if (scenario === 'empty') return { scenario, profileId: '', planId: '' }; const profileId = `ip_profile_e2e_${scenario}`; const planId = `ip_plan_e2e_${scenario}`; const profile = createProfile(profileId, now); const plan = createPlan({ scenario, profileId, planId, now }); localStorage.setItem(`tiktok.ipOperator.profiles.${scope}`, JSON.stringify([profileId])); localStorage.setItem(`tiktok.ipOperator.profile.${profileId}.${scope}`, JSON.stringify(profile)); localStorage.setItem(`tiktok.ipOperator.plans.${scope}`, JSON.stringify([planId])); localStorage.setItem(`tiktok.ipOperator.plan.${planId}.${scope}`, JSON.stringify(plan)); localStorage.setItem(`tiktok.ipOperator.activeProfileId.${scope}`, profileId); localStorage.setItem(`tiktok.ipOperator.auditTrail.${scope}`, JSON.stringify([{ id: 'ip_audit_e2e_switch', action: 'switch_profile', entityType: 'profile', entityId: profileId, userId: scope, createdAt: now, summary: `Switch current IP profile: ${profileId}`, }])); seedAccountWorkbench({ now, profileId, planId, scenario }); return { scenario, profileId, planId }; } function seedAccountWorkbench({ now, profileId, planId, scenario }) { const accountId = `ip_account_e2e_${scenario}`; const snapshotId = `ip_snapshot_e2e_${scenario}`; const proposalId = `ip_positioning_proposal_e2e_${scenario}`; const versionId = `ip_positioning_version_e2e_${scenario}`; const account = { id: accountId, userId: scope, platform: 'douyin', role: 'owned', displayName: '林川老板增长笔记', profileId, planId, homepageUrl: 'https://www.douyin.com/user/MS4wLjABAAAA_e2e', secUserId: 'MS4wLjABAAAA_e2e', accountId: 'MS4wLjABAAAA_e2e', intendedTrack: '传统行业老板 IP', intendedPersona: '增长顾问', intendedAudience: '传统行业中小企业老板', enabled: true, lastRefreshStatus: 'completed', lastRefreshedAt: now, createdAt: now, updatedAt: now, }; const works = Array.from({ length: 10 }, (_, index) => { const awemeId = `738000000${index}`; const deep = index < 3; return { id: `work_${accountId}_${awemeId}`, accountId, awemeId, title: index === 0 ? '老板 IP 如何避免成为广告号' : `老板增长内容复盘 ${index + 1}`, desc: index === 0 ? '老板 IP 如何避免成为广告号,先讲信任再讲产品。' : `传统老板账号第 ${index + 1} 条内容复盘`, coverUrl: index === 0 ? 'http://127.0.0.1:9/expired-douyin-cover.jpg' : '', coverCandidates: index === 0 ? [ 'http://127.0.0.1:9/expired-douyin-cover.jpg', 'data:image/svg+xml;charset=UTF-8,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2272%22 height=%2296%22%3E%3Crect width=%2272%22 height=%2296%22 fill=%22%230f766e%22/%3E%3C/svg%3E', ] : [], publishTime: now, url: `https://www.douyin.com/video/${awemeId}`, metrics: { playCount: 10000 - index * 600, likeCount: 320 - index * 12, commentCount: 46 - index * 3, collectCount: 80 - index * 4, shareCount: 20 - index, }, interactionScore: 320 - index * 12 + (46 - index * 3) * 4 + (80 - index * 4) * 3 + (20 - index) * 5, isDeepSampled: deep, structure: { hook: '为什么你的老板号越发越像广告?', topic: '老板 IP 信任表达', style: '问题/避坑表达', cta: '评论区留下最卡的问题', }, comments: deep ? Array.from({ length: 30 }, (_, commentIndex) => ({ id: `comment_${index + 1}_${commentIndex + 1}`, workId: `work_${accountId}_${awemeId}`, text: commentIndex % 3 === 0 ? '我们传统行业老板确实不知道怎么讲案例' : commentIndex % 3 === 1 ? '想知道怎么把客户问题变成选题' : '不要讲太虚,最好给具体脚本结构', likeCount: 12 - (commentIndex % 5), replyCount: commentIndex % 4, authorName: `用户${commentIndex + 1}`, capturedAt: now, })) : [], capturedAt: now, }; }); const snapshot = { id: snapshotId, accountId, profile: { nickname: '林川老板增长笔记', signature: '传统行业老板 IP 增长与短视频内容转化', avatarUrl: '', followerCount: 2860, followingCount: 38, totalFavorited: 15800, awemeCount: 42, }, works, dataMode: 'data_diagnosis', evidenceItemIds: [], capturedAt: now, warnings: [], }; const proposedVersion = { accountId, targetAudience: '传统行业中小企业老板', persona: '传统行业老板增长顾问', followReason: '用真实案例和短视频结构帮助老板解决表达、信任和转化问题。', contentPillars: ['老板 IP 定位与认知纠偏', '老板表达案例与完整方法', '真实项目复盘与评论答疑'], expressionStyle: ['口语化', '案例优先', '前 3 秒直接给判断'], boundaries: ['不夸大收益', '不照搬对标账号话术', '不做无关泛流量内容'], suitableViralPatterns: ['反常识开头', '问题-方案结构', '评论问题反推选题'], evidenceItemIds: [], assumptionsToValidate: ['关注理由是否清晰', '评论痛点能否反推选题'], observeMetrics: ['播放量', '评论数', '收藏数', '涨粉'], }; const proposal = { id: proposalId, accountId, snapshotId, status: 'proposed', reason: '基于最近作品表现、重点评论和对标证据生成的定位提案。', proposedVersion, evidenceItemIds: [], createdAt: now, updatedAt: now, }; const diagnosis = { id: `ip_account_diagnosis_e2e_${scenario}`, accountId, snapshotId, mode: 'data_diagnosis', reportMarkdown: [ '# 账号诊断报告', '', '## 当前账号像什么 IP', '当前更像传统行业老板增长顾问,内容需要继续收窄到老板表达、信任和转化。', '', '## 高互动作品共性', '问题开头、具体场景、明确判断。', '', '## 评论区用户关心的问题', '用户集中关心如何讲案例、如何把客户问题变成选题。', '', '## 当前最大增长障碍', '内容主题仍有分散,用户关注理由需要稳定。', '', '## 未来 7 天优先动作', '确认定位版本,分别测试涨粉、信任、互动三个方向。', ].join('\n'), scores: { positioningClarity: 82, contentStructure: 78, interactionConversion: 75, recognizability: 80, sustainability: 76, }, evidenceItemIds: [], topWorkIds: works.slice(0, 3).map((item) => item.id), commentSampleCount: 90, createdAt: now, updatedAt: now, }; const version = { id: versionId, ...proposedVersion, version: 1, status: 'active', createdAt: now, updatedAt: now, }; const directions = [ createDirection(accountId, versionId, 'growth', '老板 IP 定位与认知纠偏', '围绕老板做内容时的常见误区和判断标准,帮助新用户快速建立正确认知。', ['播放量', '分享数', '新粉'], now), createDirection(accountId, versionId, 'trust', '老板表达案例与完整方法', '通过真实案例、表达框架和执行过程建立专业信任。', ['收藏数', '咨询意向', '关注率'], now), createDirection(accountId, versionId, 'interaction', '真实项目复盘与评论答疑', '把高互动评论归纳成问题类型,用项目复盘和集中答疑形成持续栏目。', ['评论数', '评论率', '高频问题'], now), ]; const tasks = [ createTask(accountId, 'today', 'positioning', '确认账号当前定位提案', '定位版本会约束后续方向、选题、脚本和发布包。', 95, now), createTask(accountId, 'today', 'direction', '确认涨粉破圈方向', '先稳定最影响播放和涨粉的内容方向。', 90, now), createTask(accountId, 'this_week', 'pain', '复核重点作品评论痛点', '评论问题能反推互动型选题和脚本切入点。', 82, now), createTask(accountId, 'later', 'publish_pack', '绑定发布包与真实作品', '发布后绑定作品才能形成复盘闭环。', 72, now), ]; const binding = { id: `publish_binding_${planId}_1`, publishPackageId: `${planId}_publish_1`, accountId, awemeId: works[0].awemeId, workUrl: works[0].url, status: 'auto_matched', matchScore: 86, matchReason: '根据标题/文案相似度自动匹配,请人工复核。', createdAt: now, updatedAt: now, }; saveEntity('tiktok.ipOperator.accounts', 'tiktok.ipOperator.account.', account); saveEntity('tiktok.ipOperator.accountSnapshots', 'tiktok.ipOperator.accountSnapshot.', snapshot); saveEntity('tiktok.ipOperator.accountDiagnoses', 'tiktok.ipOperator.accountDiagnosis.', diagnosis); saveEntity('tiktok.ipOperator.positioningProposals', 'tiktok.ipOperator.positioningProposal.', proposal); saveEntity('tiktok.ipOperator.positioningVersions', 'tiktok.ipOperator.positioningVersion.', version); directions.forEach((item) => saveEntity('tiktok.ipOperator.contentDirections', 'tiktok.ipOperator.contentDirection.', item)); tasks.forEach((item) => saveEntity('tiktok.ipOperator.operationTasks', 'tiktok.ipOperator.operationTask.', item)); saveEntity('tiktok.ipOperator.publishBindings', 'tiktok.ipOperator.publishBinding.', binding); } function createDirection(accountId, positioningVersionId, role, title, purpose, observeMetrics, now) { return { id: `direction_${accountId}_${role}`, accountId, positioningVersionId, role, title, targetAudience: role === 'growth' ? '尚未关注账号的新用户' : role === 'trust' ? '正在判断账号是否可靠的用户' : '有具体问题并愿意评论追问的用户', purpose, sourceEvidenceIds: [], viralPatternRefs: ['反常识开头', '问题-方案结构'], commentPainRefs: [], topicIds: [], cadenceSuggestion: role === 'growth' ? '每周 2-3 条' : '每周 1-2 条', observeMetrics, createdAt: now, updatedAt: now, }; } function createTask(accountId, column, type, title, reason, growthImpactScore, now) { return { id: `task_${accountId}_${type}_${column}`, accountId, column, type, title, reason, growthImpactScore, relatedEvidenceIds: [], createdAt: now, updatedAt: now, }; } function saveEntity(indexKey, prefix, entity) { const scopedIndex = `${indexKey}.${scope}`; const ids = JSON.parse(localStorage.getItem(scopedIndex) || '[]'); localStorage.setItem(scopedIndex, JSON.stringify(Array.from(new Set([entity.id, ...ids])))); localStorage.setItem(`${prefix}${entity.id}.${scope}`, JSON.stringify(entity)); } function clearIpOperatorData() { for (const key of Object.keys(localStorage)) { if ( key.startsWith('tiktok.ipOperator.') || key === 'videoWorkflow.authSession' || key === 'videoWorkflow.topicPool.items' ) { localStorage.removeItem(key); } } } function createProfile(id, now) { return { id, userId: scope, name: 'E2E IP Operator Profile', stage: 'started', identity: 'Traditional industry consultant for local business owners', industry: 'Local service business', targetAudience: 'Owners who need practical IP-driven content and trust conversion', audiencePainPoints: ['Content looks like advertising', 'No stable topic system'], productsOrServices: 'IP positioning and content operation consulting', personalStories: ['Helped a local service team turn cases into short video topics'], expertise: ['Positioning', 'Topic planning', 'Script diagnosis'], expressionStyle: ['Direct', 'Practical'], boundaries: ['No exaggerated income promise'], goals: ['Build trust', 'Collect consultation leads'], questionnaire: [], createdAt: now, updatedAt: now, }; } function createPlan({ scenario, profileId, planId, now }) { const topics = createTopics(); const scripts = createScripts(topics); const failed = scenario === 'failed'; const needsInput = scenario === 'needs_input'; return { id: planId, userId: scope, profileId, status: failed ? 'failed' : needsInput ? 'needs_input' : 'ready', generationProgress: [ { stage: 'intake_summary', label: 'Intake summary', status: 'completed', durationMs: 120 }, { stage: 'diagnosis', label: 'Diagnosis', status: failed ? 'failed' : 'completed', durationMs: 120, failureCode: failed ? 'llm_malformed_json' : undefined, errorMessage: failed ? 'Malformed JSON in diagnosis stage' : undefined }, ], qualityCheck: { overallScore: needsInput ? 64 : failed ? 40 : 88, positioningClarityScore: needsInput ? 60 : 90, audienceClarityScore: needsInput ? 62 : 86, evidenceSupportScore: needsInput ? 50 : 84, benchmarkTransferScore: needsInput ? 58 : 88, topicUsabilityScore: needsInput ? 65 : 91, passed: !needsInput && !failed, blockingIssues: needsInput ? ['Missing real cases and proof material'] : failed ? ['Generation failed before quality gate'] : [], improvementSuggestions: needsInput ? ['Add two real client cases before syncing topics'] : ['Validate the first three full scripts with real material.'], }, intakeSummary: { identitySummary: 'Local business IP operator', audienceSummary: 'Traditional business owners', advantageSummary: 'Can translate business cases into practical content', businessGoalSummary: 'Build trust and collect consultation leads', missingInputs: needsInput ? [{ type: 'case', description: 'Add real client before-after cases', priority: 'high' }] : [], }, diagnosis: failed ? undefined : { positioningStatement: 'A practical operator who turns local business experience into trusted owner IP content.', targetAudience: { summary: 'Owners who need short video content but do not want to become ad accounts.', painPoints: ['No topic system', 'Content lacks trust', 'Hard to convert'], }, marketOpportunity: 'Many local businesses have real cases but lack content packaging.', ipType: 'Operator partner', personaTags: ['Practical', 'Case-driven', 'Trust-first'], differentiation: 'Turns benchmark hot points into positioning-matched topics instead of copying formats.', contentTracks: ['Positioning diagnosis', 'Trust cases', 'Conversion path'], monetizationPath: 'Consultation and operation service leads.', risks: ['Avoid exaggerated conversion promises'], alternativeDirections: ['Focus on one local industry first'], missingInputs: needsInput ? [{ type: 'case', description: 'Add real proof material', priority: 'high' }] : [], }, benchmarkAnalyses: failed ? [] : [{ benchmarkId: 'benchmark_e2e_1', accountName: 'Benchmark Owner Account', positioning: 'Direct business advice for owners', contentColumns: ['Pain point diagnosis', 'Case breakdown'], viralPatterns: ['Question hook', 'Concrete contrast'], scriptStructure: 'Hook - pain - viewpoint - case - action', conversionPath: 'Content trust to consultation', borrowablePoints: ['Direct question hooks', 'Case contrast'], nonCopyablePoints: ['Personal background', 'Exact industry claims'], migrationDirection: 'Use the hook logic, replace the case and judgement with this IP assets.', fitScore: 86, }], opportunityMap: failed ? [] : [{ id: 'ip_opp_e2e_1', type: 'Trust diagnosis', fitScore: 90, reason: 'Matches audience pain and available expertise.', audiencePainPoint: 'Users do not trust product-only content.', requiredMaterials: ['Before-after case'], extendableTopics: ['Ad account problem', 'Trust building'], riskBoundary: 'No guaranteed result claim.', }], topics: failed ? [] : topics, scripts: failed ? [] : scripts, sevenDayTestPlan: failed ? [] : topics.slice(0, 7).map((topic, index) => ({ day: index + 1, topicId: topic.id, topicTitle: topic.title, testGoal: 'Validate hook clarity and trust response.', contentType: topic.trafficLayer, shootingFocus: 'Talk to camera with one real scenario.', observeMetrics: ['Completion', 'Comment quality', 'Consultation intent'], reviewQuestions: ['Did users understand the pain?', 'Was the CTA too hard?'], })), thirtyDayDirection: failed ? undefined : { columnStructure: [ { column: 'Positioning diagnosis', ratio: 40, role: 'Trust entry' }, { column: 'Trust content', ratio: 35, role: 'Relationship building' }, { column: 'Conversion path', ratio: 25, role: 'Lead collection' }, ], weeklyFocus: ['Validate hooks', 'Add case material', 'Test conversion CTA', 'Review topic columns'], materialDirections: ['Customer doubt list', 'Before-after cases', 'Service process screenshots'], iterationPath: ['Keep high-comment questions', 'Rewrite weak hooks', 'Promote proven topics'], }, evidenceItems: [], commentPainInsights: [], accountStrategyReports: failed ? [] : createAccountStrategyReports({ scenario, planId, now }), calibrationRecords: failed ? [] : createCalibrationRecords({ scenario, planId, now }), publishRetrospectives: failed ? [] : createPublishRetrospectives({ scenario, planId, now }), commentLabelSystems: [], contentCalendar: failed ? [] : createContentCalendar({ planId, topics, now }), publishPackages: failed ? [] : createPublishPackages({ planId, topics, scripts, now }), retrospectiveFollowUpTopics: [], matrixAccounts: [], missingInputs: needsInput ? [{ type: 'case', description: 'Add real client before-after cases', priority: 'high' }] : [], errorMessage: failed ? 'Generation stopped because diagnosis JSON was malformed.' : undefined, createdAt: now, updatedAt: now, }; } function createAccountStrategyReports({ scenario, planId, now }) { const accountId = `ip_account_e2e_${scenario}`; const snapshotId = `ip_snapshot_e2e_${scenario}`; const workId = `work_${accountId}_7380000000`; return [{ id: `ip_strategy_report_e2e_${scenario}`, accountId, snapshotId, positioningProposalId: `ip_positioning_proposal_e2e_${scenario}`, sourceMode: 'llm', sourceLabel: 'LLM 证据诊断', diagnosisSummary: { accountSnapshot: '账号已读取最近作品和重点评论样本。', currentIpGuess: '传统行业老板增长顾问', actualAudience: '传统行业中小企业老板', positioningMismatch: '需要减少泛工具话题,强化经营问题和真实案例。', strongestFollowReason: '能把老板经营问题拆成短视频表达和执行步骤。', biggestGrowthBlocker: '定位校准和发布复盘还需要持续继承。', highInteractionPattern: '先指出老板号误区,再给可执行步骤。', commentPainSummary: '用户集中关心案例怎么讲、问题怎么变选题。', sevenDayPriority: '围绕经营问题继续测试 3 条内容。', }, evidenceRefs: [{ id: `strategy_ref_${scenario}_work_1`, sourceType: 'owned_work', sourceId: workId, label: '高互动经营问题作品', quote: '收藏和评论集中说明用户需要可执行的老板号内容顺序。', reason: '支持继续测试“经营问题拆解”方向,而不是复制原作品简介。', confidence: 'medium', gaps: ['仍需发布后转化表现'], analyzed: true, }], directions: [], taskSuggestions: [], appliedCalibrationIds: [`calibration_${planId}_1`], appliedCalibrationSummary: ['已采用用户校准:减少纯工具合集,强调老板经营问题。'], confidenceLevel: 'medium', evidenceGaps: ['仍缺发布后复盘数据的长期对比'], dataScopeSummary: { workCount: 10, commentCount: 90, hasPositioningVersion: true, calibrationCount: 1, publishBindingCount: 1, }, createdAt: now, updatedAt: now, }]; } function createCalibrationRecords({ scenario, planId, now }) { const accountId = `ip_account_e2e_${scenario}`; return [{ id: `calibration_${planId}_1`, accountId, reportId: `ip_strategy_report_e2e_${scenario}`, source: 'manual_calibration', accuracy: 'partial', targetAudienceNotes: '更偏传统行业中小企业老板。', positioningNotes: '减少纯工具合集,强调老板经营问题。', personaNotes: '懂业务的增长顾问。', forbiddenTopics: ['纯工具合集'], forbiddenExpressions: ['保姆级万能'], confirmedDirectionIds: [`direction_${accountId}_trust`], rejectedDirectionIds: [], rejectedEvidenceIds: [], operatorExperienceNotes: '历史内容里案例拆解更容易带来收藏和有效评论。', createdAt: now, updatedAt: now, }]; } function createPublishRetrospectives({ scenario, planId, now }) { const accountId = `ip_account_e2e_${scenario}`; return [{ id: `publish_review_${planId}_1`, accountId, publishPackageId: `${planId}_publish_1`, bindingId: `publish_binding_${planId}_1`, workId: `work_${accountId}_7380000000`, outcome: 'met_expectation', expectedGoal: ['验证信任表达是否能带来评论和关注'], actualSignals: ['收藏和评论达到预期', '评论集中在案例怎么讲'], diagnosis: '信任表达方向可继续测试,但需要增加真实案例材料。', nextAction: 'continue', calibrationRecordId: `calibration_${planId}_1`, createdAt: now, updatedAt: now, }]; } function createTopics() { return Array.from({ length: 12 }, (_, index) => ({ id: `ip_topic_e2e_${index + 1}`, title: index === 0 ? 'Why owner IP should not look like an ad account' : `Owner IP trust topic ${index + 1}`, column: index % 3 === 0 ? 'Positioning diagnosis' : index % 3 === 1 ? 'Trust content' : 'Conversion path', trafficLayer: index < 4 ? 'vertical' : index < 8 ? 'conversion' : 'broad', contentGoal: 'Help the target user understand the trust problem and next action', priority: index < 4 ? 'high' : index < 9 ? 'medium' : 'low', qualityLevel: index < 4 ? 'make_now' : index < 8 ? 'polish_first' : 'needs_material', fitReason: 'Derived from benchmark hooks and adapted to this IP positioning', source: 'Benchmark migration', requiredMaterials: ['Real case', 'Service before-after comparison'], scriptStatus: index < 3 ? 'full' : 'outline', riskNote: 'Avoid hard selling and exaggerated claims', })); } function createScripts(topics) { return topics.map((topic, index) => ({ id: `ip_script_e2e_${index + 1}`, topicId: topic.id, type: index < 3 ? 'full' : 'outline', title: topic.title, hook: 'If your account keeps introducing products, users will treat it as advertising.', painPoint: 'The content has information but no trust context.', viewpoint: 'Owner IP must first transmit judgement, not product inventory.', caseOrMethod: 'Use one benchmark hook, one real scenario, and one conversion boundary.', goldenSentence: 'Trust comes before transaction.', closingCta: 'Save this and check whether your next video is selling or building trust.', fullScript: index < 3 ? 'Opening: many owner accounts look professional but still fail to convert. Middle: users do not reject business, they reject content that only pushes products. Example: when a local service owner changed from product introductions to decision-making stories, consultation quality improved. Ending: the next video should answer one real customer doubt before mentioning the product.' : '', shootingTips: ['Talk to camera', 'Use one service case'], subtitleHighlights: ['Do not sell first', 'Show judgement first'], replaceableSlots: ['Insert local case'], riskNote: 'Do not claim guaranteed conversion.', })); } function createContentCalendar({ planId, topics, now }) { return [{ id: `${planId}_calendar_1`, planId, topicId: topics[0]?.id, scriptId: 'ip_script_e2e_1', date: now.slice(0, 10), timeSlot: '19:30', platform: 'douyin', accountName: '林川老板增长笔记', pillar: '信任建立内容', title: '老板 IP 如何避免成为广告号', contentGoal: '验证信任表达是否能带来评论和关注', materialNeeds: ['真实账号截图', '客户问题截图'], evidenceItemIds: [], painInsightIds: [], status: 'ready_for_review', publishPackageId: `${planId}_publish_1`, createdAt: now, updatedAt: now, }]; } function createPublishPackages({ planId, topics, scripts, now }) { return [{ id: `${planId}_publish_1`, calendarItemId: `${planId}_calendar_1`, topicId: topics[0]?.id || '', scriptId: scripts[0]?.id || '', platform: 'douyin', accountName: '林川老板增长笔记', titleOptions: ['老板 IP 如何避免成为广告号', '为什么你的老板号越发越不被信任'], coverSuggestions: ['左侧:广告号,右侧:信任号', '老板别再只讲产品'], caption: '老板 IP 如何避免成为广告号,先讲信任再讲产品。', scriptText: scripts[0]?.fullScript || scripts[0]?.hook || '', hashtags: ['老板IP', '短视频运营', '账号定位'], materialFiles: [ { id: 'material_1', name: '账号主页截图', status: 'missing' }, { id: 'material_2', name: '客户问题截图', status: 'missing' }, ], scheduleSuggestion: '今天 19:30 人工发布,发布后回填作品链接。', isOriginal: true, isDraft: true, materialChecklist: [ { id: 'material_check_1', label: '确认案例素材可公开', checked: false, required: true }, { id: 'material_check_2', label: '检查封面文字不夸张', checked: true, required: true }, ], riskChecklist: [ { id: 'risk_check_1', label: '不承诺具体收益', checked: true, required: true }, { id: 'risk_check_2', label: '不使用诱导互动话术', checked: true, required: true }, ], platformVariants: { xiaohongshu: { title: '老板 IP 别再拍成广告号', coverText: '先讲信任,再讲产品', imageNoteOutline: ['问题', '原因', '改法'], hashtags: ['老板IP', '内容运营'], }, douyin: { firstThreeSecondsHook: '为什么你的老板号越发越像广告?', shotList: ['正面口播', '账号截图', '标题对比'], spokenScript: scripts[0]?.fullScript || '', subtitleEmphasis: ['别急着卖产品', '先给关注理由'], }, wechat: { calmerTitle: '老板内容如何建立信任', intro: '很多老板号的问题不是不专业,而是太像广告。', body: '先讲清楚用户问题,再放服务能力。', endingCta: '欢迎把你的账号问题发来一起看。', }, }, evidenceItemIds: [], painInsightIds: [], status: 'ready_for_review', createdAt: now, updatedAt: now, }]; } window.__seedIpOperatorScenario = seedIpOperatorScenario; })();