|
@@ -37,10 +37,247 @@
|
|
|
createdAt: now,
|
|
createdAt: now,
|
|
|
summary: `Switch current IP profile: ${profileId}`,
|
|
summary: `Switch current IP profile: ${profileId}`,
|
|
|
}]));
|
|
}]));
|
|
|
|
|
+ seedAccountWorkbench({ now, profileId, planId, scenario });
|
|
|
|
|
|
|
|
return { scenario, profileId, planId };
|
|
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() {
|
|
function clearIpOperatorData() {
|
|
|
for (const key of Object.keys(localStorage)) {
|
|
for (const key of Object.keys(localStorage)) {
|
|
|
if (
|
|
if (
|
|
@@ -168,6 +405,16 @@
|
|
|
materialDirections: ['Customer doubt list', 'Before-after cases', 'Service process screenshots'],
|
|
materialDirections: ['Customer doubt list', 'Before-after cases', 'Service process screenshots'],
|
|
|
iterationPath: ['Keep high-comment questions', 'Rewrite weak hooks', 'Promote proven topics'],
|
|
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' }] : [],
|
|
missingInputs: needsInput ? [{ type: 'case', description: 'Add real client before-after cases', priority: 'high' }] : [],
|
|
|
errorMessage: failed ? 'Generation stopped because diagnosis JSON was malformed.' : undefined,
|
|
errorMessage: failed ? 'Generation stopped because diagnosis JSON was malformed.' : undefined,
|
|
|
createdAt: now,
|
|
createdAt: now,
|
|
@@ -175,6 +422,98 @@
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ 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() {
|
|
function createTopics() {
|
|
|
return Array.from({ length: 12 }, (_, index) => ({
|
|
return Array.from({ length: 12 }, (_, index) => ({
|
|
|
id: `ip_topic_e2e_${index + 1}`,
|
|
id: `ip_topic_e2e_${index + 1}`,
|
|
@@ -183,6 +522,7 @@
|
|
|
trafficLayer: index < 4 ? 'vertical' : index < 8 ? 'conversion' : 'broad',
|
|
trafficLayer: index < 4 ? 'vertical' : index < 8 ? 'conversion' : 'broad',
|
|
|
contentGoal: 'Help the target user understand the trust problem and next action',
|
|
contentGoal: 'Help the target user understand the trust problem and next action',
|
|
|
priority: index < 4 ? 'high' : index < 9 ? 'medium' : 'low',
|
|
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',
|
|
fitReason: 'Derived from benchmark hooks and adapted to this IP positioning',
|
|
|
source: 'Benchmark migration',
|
|
source: 'Benchmark migration',
|
|
|
requiredMaterials: ['Real case', 'Service before-after comparison'],
|
|
requiredMaterials: ['Real case', 'Service before-after comparison'],
|
|
@@ -213,5 +553,84 @@
|
|
|
}));
|
|
}));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ 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;
|
|
window.__seedIpOperatorScenario = seedIpOperatorScenario;
|
|
|
})();
|
|
})();
|