feat: align web platforms to domestic rollout

This commit is contained in:
kris
2026-03-23 08:38:51 +08:00
parent d7132fe932
commit 9a753f60d8
2 changed files with 61 additions and 60 deletions

View File

@@ -35,6 +35,14 @@ const appState = {
};
const INTEGRATION_ORDER = ["local_model", "cutvideo", "huobao", "n8n", "asr"];
const ACTIVE_PLATFORMS = [
{ value: "douyin", label: "抖音" },
{ value: "xiaohongshu", label: "小红书" },
{ value: "bilibili", label: "哔哩哔哩" },
{ value: "kuaishou", label: "快手" },
{ value: "wechat_video", label: "微信视频号" }
];
const ACTIVE_PLATFORM_CHIPS = ["全平台", "抖音", "小红书", "B站", "快手", "视频号"];
const INTEGRATION_META = {
local_model: {
label: "本机模型",
@@ -81,6 +89,24 @@ function safeArray(value) {
return Array.isArray(value) ? value : [];
}
function getPlatformOptions() {
return ACTIVE_PLATFORMS.map((item) => ({ value: item.value, label: item.label }));
}
function normalizePlatformValue(value, fallback = "douyin") {
const normalized = String(value || "").trim().toLowerCase();
if (!normalized) return fallback;
const byValue = ACTIVE_PLATFORMS.find((item) => item.value === normalized);
if (byValue) return byValue.value;
const byLabel = ACTIVE_PLATFORMS.find((item) => item.label === value);
return byLabel?.value || fallback;
}
function platformLabel(value) {
const matched = ACTIVE_PLATFORMS.find((item) => item.value === normalizePlatformValue(value, ""));
return matched?.label || String(value || "抖音");
}
function escapeHtml(value) {
return String(value ?? "")
.replaceAll("&", "&")
@@ -2136,7 +2162,7 @@ function renderReviewScreen() {
<h4>${escapeHtml(review.title)}</h4>
<p>${escapeHtml(brief(review.highlights || review.next_actions || review.notes || "已保存复盘,待继续补充表现数据。", 92))}</p>
<div class="task-meta">
<span class="tag blue">${escapeHtml(review.platform || "douyin")}</span>
<span class="tag blue">${escapeHtml(platformLabel(review.platform || "douyin"))}</span>
<span class="tag ${statusTone(review.verdict || "blue")}">${escapeHtml(review.verdict || "已记录")}</span>
${review.publish_url ? `<a class="tag" href="${escapeHtml(review.publish_url)}" target="_blank" rel="noreferrer">打开链接</a>` : ""}
<span class="tag clickable-tag" data-action="open-review-edit" data-review-id="${escapeHtml(review.id)}">编辑</span>
@@ -2221,8 +2247,7 @@ function renderTopbar() {
topPills[2].textContent = `任务 ${formatNumber(appState.dashboard?.recent_jobs?.length || 0)}`;
}
if (platforms) {
const chips = ["全平台", "抖音", "小红书", "B站", "YouTube"];
platforms.innerHTML = chips.map((label, index) => `<span class="chip ${index === 0 ? "active" : ""}">${escapeHtml(label)}</span>`).join("");
platforms.innerHTML = ACTIVE_PLATFORM_CHIPS.map((label, index) => `<span class="chip ${index === 0 ? "active" : ""}">${escapeHtml(label)}</span>`).join("");
}
}
@@ -2399,18 +2424,11 @@ function openImportHomepageAction() {
const assistants = getAssistantOptions(project.id);
openActionModal({
title: "导入主页并同步",
description: "适合抖音 / 小红书 / B站 / YouTube 主页。先建内容源,再触发同步与分析。",
description: "适合抖音 / 小红书 / B站 / 快手 / 视频号主页。先建内容源,再触发同步与分析。",
submitLabel: "开始同步",
fields: [
{ name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() },
{ name: "platform", label: "平台", type: "select", value: "douyin", options: [
{ value: "douyin", label: "抖音" },
{ value: "xiaohongshu", label: "小红书" },
{ value: "bilibili", label: "哔哩哔哩" },
{ value: "youtube", label: "YouTube" },
{ value: "kuaishou", label: "快手" },
{ value: "wechat_video", label: "微信视频号" }
] },
{ name: "platform", label: "平台", type: "select", value: "douyin", options: getPlatformOptions() },
{ name: "title", label: "标题", placeholder: "例如:创业口播对标账号" },
{ name: "handle", label: "账号名 / handle", placeholder: "可选" },
{ name: "sourceUrl", label: "主页链接", type: "url", placeholder: "https://..." },
@@ -2420,12 +2438,13 @@ function openImportHomepageAction() {
onSubmit: async (values) => {
if (!values.sourceUrl?.trim()) throw new Error("请填写主页链接");
const projectId = values.projectId || project.id;
const platform = normalizePlatformValue(values.platform, "douyin");
const source = await storyforgeFetch("/v2/content-sources", {
method: "POST",
body: {
project_id: projectId,
source_kind: "creator_account",
platform: values.platform || "douyin",
platform,
handle: values.handle || "",
source_url: values.sourceUrl.trim(),
title: values.title || values.handle || "主页对标",
@@ -2439,7 +2458,7 @@ function openImportHomepageAction() {
knowledge_base_id: getProjectKnowledgeBases(projectId)[0]?.id || kb?.id || "",
assistant_id: values.assistantId || "",
content_source_id: source.id,
platform: values.platform || "douyin",
platform,
handle: values.handle || "",
source_url: values.sourceUrl.trim(),
title: values.title || values.handle || "主页对标",
@@ -2469,14 +2488,7 @@ function openImportSelectedAccountAction() {
submitLabel: currentSource ? "继续同步" : "导入并同步",
fields: [
{ name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() },
{ name: "platform", label: "平台", type: "select", value: "douyin", options: [
{ value: "douyin", label: "抖音" },
{ value: "xiaohongshu", label: "小红书" },
{ value: "bilibili", label: "哔哩哔哩" },
{ value: "youtube", label: "YouTube" },
{ value: "kuaishou", label: "快手" },
{ value: "wechat_video", label: "微信视频号" }
] },
{ name: "platform", label: "平台", type: "select", value: normalizePlatformValue(currentSource?.platform || "douyin"), options: getPlatformOptions() },
{ name: "title", label: "内容源标题", value: currentSource?.title || `${account.nickname || account.douyin_id || "对标账号"} 对标主页` },
{ name: "handle", label: "账号标识", value: currentSource?.handle || account.douyin_id || "" },
{ name: "sourceUrl", label: "主页链接", type: "url", value: currentSource?.source_url || account.profile_url || "", placeholder: "https://..." },
@@ -2488,6 +2500,7 @@ function openImportSelectedAccountAction() {
onSubmit: async (values) => {
if (!values.sourceUrl?.trim()) throw new Error("请先填写主页链接");
const projectId = values.projectId || project.id;
const platform = normalizePlatformValue(values.platform, "douyin");
const source = currentSource && currentSource.project_id === projectId
? currentSource
: await storyforgeFetch("/v2/content-sources", {
@@ -2495,7 +2508,7 @@ function openImportSelectedAccountAction() {
body: {
project_id: projectId,
source_kind: "creator_account",
platform: values.platform || "douyin",
platform,
handle: values.handle || "",
source_url: values.sourceUrl.trim(),
title: values.title || values.handle || account.nickname || "对标主页",
@@ -2512,7 +2525,7 @@ function openImportSelectedAccountAction() {
knowledge_base_id: getProjectKnowledgeBases(projectId)[0]?.id || kb?.id || "",
assistant_id: values.assistantId || "",
content_source_id: source.id,
platform: values.platform || "douyin",
platform,
handle: values.handle || account.douyin_id || "",
source_url: values.sourceUrl.trim(),
title: values.title || account.nickname || values.handle || "对标主页",
@@ -2993,12 +3006,7 @@ function openGenerateCopyAction(defaults = {}) {
submitLabel: "开始生成",
fields: [
{ name: "brief", label: "创作需求", type: "textarea", rows: 5, value: defaults.brief || getJobSeedBrief(sourceJob), placeholder: "例如:给创业者写一条 60 字内的短视频开场文案" },
{ name: "platform", label: "平台", type: "select", value: "抖音", options: [
{ value: "抖音", label: "抖音" },
{ value: "小红书", label: "小红书" },
{ value: "哔哩哔哩", label: "哔哩哔哩" },
{ value: "YouTube", label: "YouTube" }
] },
{ name: "platform", label: "平台", type: "select", value: normalizePlatformValue(defaults.platform || "douyin"), options: getPlatformOptions() },
{ name: "audience", label: "受众", value: "创业者" },
{ name: "extraRequirements", label: "额外要求", placeholder: "例如:强结论开头,结尾带 CTA" }
],
@@ -3008,7 +3016,7 @@ function openGenerateCopyAction(defaults = {}) {
method: "POST",
body: {
brief: values.brief.trim(),
platform: values.platform || "抖音",
platform: platformLabel(values.platform || "douyin"),
audience: values.audience || "创业者",
extra_requirements: values.extraRequirements || "",
knowledge_base_ids: safeArray(assistant.knowledge_base_ids)
@@ -3127,14 +3135,7 @@ function openReviewAction(defaults = {}) {
{ name: "title", label: "标题", value: existingReview?.title || defaults.title || sourceJob?.title || "", placeholder: "例如:创业口播 3 月 22 日复盘" },
{ name: "sourceJobId", label: "关联任务", type: "select", value: existingReview?.source_job_id || defaults.sourceJobId || sourceJob?.id || "", options: [{ value: "", label: "不关联任务" }, ...getCompletedJobOptions()] },
{ name: "assistantId", label: "负责 Agent", type: "select", value: existingReview?.assistant_id || getSelectedAssistant()?.id || assistants[0]?.value || "", options: [{ value: "", label: "先不绑定" }, ...assistants] },
{ name: "platform", label: "平台", type: "select", value: existingReview?.platform || defaults.platform || "douyin", options: [
{ value: "douyin", label: "抖音" },
{ value: "xiaohongshu", label: "小红书" },
{ value: "bilibili", label: "哔哩哔哩" },
{ value: "youtube", label: "YouTube" },
{ value: "kuaishou", label: "快手" },
{ value: "wechat_video", label: "微信视频号" }
] },
{ name: "platform", label: "平台", type: "select", value: normalizePlatformValue(existingReview?.platform || defaults.platform || "douyin"), options: getPlatformOptions() },
{ name: "contentType", label: "内容类型", type: "select", value: existingReview?.content_type || "video", options: [
{ value: "video", label: "视频" },
{ value: "image_text", label: "图文" },
@@ -3164,7 +3165,7 @@ function openReviewAction(defaults = {}) {
source_job_id: values.sourceJobId || "",
assistant_id: values.assistantId || "",
title: values.title.trim(),
platform: values.platform || "douyin",
platform: normalizePlatformValue(values.platform, "douyin"),
content_type: values.contentType || "video",
publish_url: values.publishUrl || "",
published_at: values.publishedAt || "",

View File

@@ -94,7 +94,8 @@
<span class="chip">抖音</span>
<span class="chip">小红书</span>
<span class="chip">B站</span>
<span class="chip">YouTube</span>
<span class="chip">快手</span>
<span class="chip">视频号</span>
</div>
</div>
<div class="topbar-right">
@@ -244,10 +245,10 @@
</div>
<div class="entity-card pad">
<div class="entity-cell">
<div class="avatar-lg">YT</div>
<div class="avatar-lg">KS</div>
<div>
<div class="cell-title">Grow With Data</div>
<div class="cell-desc">YouTube · Knowledge Shorts</div>
<div class="cell-title">老K拆增长</div>
<div class="cell-desc">快手 · 知识短视频</div>
</div>
</div>
<div class="entity-meta">
@@ -416,8 +417,8 @@
</div>
</div>
<div class="entity-card pad">
<div class="cell-title">海外 Shorts 试水项目</div>
<div class="cell-desc">已确定平台为 YouTube,尚未正式开账号,先做题材验证</div>
<div class="cell-title">视频号试水项目</div>
<div class="cell-desc">已确定平台为微信视频号,尚未正式开账号,先做题材验证</div>
<div class="entity-meta">
<span class="tag orange">待绑定账号</span>
<span class="tag">先做调研</span>
@@ -437,7 +438,7 @@
<div class="insight-card">
<h4>导入单条作品</h4>
<ul>
<li>支持抖音 / 小红书 / B站 / 视频号 / YouTube 链接</li>
<li>支持抖音 / 小红书 / B站 / 视频号 / 快手链接</li>
<li>可选择“手动关联 Agent”或“自动关联最近使用 Agent”</li>
<li>进入导入分析 Agent 队列后再分类</li>
</ul>
@@ -445,7 +446,7 @@
<div class="insight-card">
<h4>导入创作者主页</h4>
<ul>
<li>输入抖音、小红书、B站、快手、视频号、YouTube 主页链接</li>
<li>输入抖音、小红书、B站、快手、视频号主页链接</li>
<li>自动建立参考账号卡片</li>
<li>也可手动指定 Agent</li>
</ul>
@@ -515,7 +516,7 @@
<p>已绑定 · 最近同步:今天 08:46 · 当前图文收藏信号强于视频信号</p>
</div>
<div class="task-item">
<h4>视频号 / 快手 / YouTube / 哔哩哔哩</h4>
<h4>视频号 / 快手 / 哔哩哔哩</h4>
<p>不绑定也能先做预调研。</p>
</div>
</div>
@@ -806,8 +807,8 @@
</div>
</div>
<div class="task-item">
<h4>Grow With Data</h4>
<p>YouTube · 关联 Agent海外 Shorts 助手 · 最近更新3 天前</p>
<h4>老K拆增长</h4>
<p>快手 · 关联 Agent短视频节奏助手 · 最近更新3 天前</p>
<div class="task-meta">
<span class="tag">等待下次抓取</span>
</div>
@@ -875,8 +876,8 @@
</div>
</div>
<div class="review-card">
<h4>Grow With Data · 《3 hooks for Shorts</h4>
<p>海外 Shorts 助手判断:更适合补充节奏和结构,不建议直接照搬表达。</p>
<h4>老K拆增长 · 《3 个留人钩子拆解</h4>
<p>短视频节奏助手判断:更适合补充节奏和结构,不建议直接照搬表达。</p>
<div class="task-meta">
<span class="tag">结构可借</span>
<span class="tag orange">表达不直接照搬</span>
@@ -1194,7 +1195,7 @@
<div class="playbook-list">
<div class="playbook-item active">
<h4>强观点短视频开头模板</h4>
<p>抖音 / YouTube Shorts · 反常识开头 · 高评论</p>
<p>抖音 / 快手短视频 · 反常识开头 · 高评论</p>
</div>
<div class="playbook-item">
<h4>高信任教育图文结构模板</h4>
@@ -1202,7 +1203,7 @@
</div>
<div class="playbook-item">
<h4>案例拆解型长视频切片模板</h4>
<p>B站 / YouTube · 适合做知识型切片</p>
<p>B站 / 视频号 · 适合做知识型切片</p>
</div>
</div>
</div>
@@ -1237,7 +1238,7 @@
<h4>覆盖平台</h4>
<ul>
<li>抖音 / 小红书 / 快手</li>
<li>微信视频号 / YouTube / 哔哩哔哩</li>
<li>微信视频号 / 快手 / 哔哩哔哩</li>
<li>按勾选平台先跑市场调研</li>
</ul>
</div>
@@ -1264,7 +1265,6 @@
<span class="chip active">小红书</span>
<span class="chip">快手</span>
<span class="chip">微信视频号</span>
<span class="chip">YouTube</span>
<span class="chip">哔哩哔哩</span>
</div>
@@ -1321,7 +1321,7 @@
</div>
<div class="task-item">
<h4>分镜助手-副业避坑</h4>
<p>学习源:反常识开头 + 失败案例 Playbook · 平台:抖音 / YouTube Shorts · 变现:广告合作</p>
<p>学习源:反常识开头 + 失败案例 Playbook · 平台:抖音 / 快手短视频 · 变现:广告合作</p>
<div class="task-meta">
<span class="tag orange">待补学习集</span>
<span class="tag">主模型:豆包</span>
@@ -1685,7 +1685,7 @@
<div class="day"><strong>周四</strong><div class="slot">B站长视频切片<br />18:30</div></div>
<div class="day"><strong>周五</strong><div class="slot">抖音:栏目连载 03<br />20:00</div></div>
<div class="day"><strong>周六</strong><div class="slot">小红书:案例图文<br />13:00</div></div>
<div class="day"><strong>周日</strong><div class="slot">YouTube ShortsA/B 版<br />21:00</div></div>
<div class="day"><strong>周日</strong><div class="slot">视频号A/B 版<br />21:00</div></div>
</div>
</div>
@@ -1866,7 +1866,7 @@
<p>文案积分 265 / 封面积分 182 / 视频积分 41。主要消耗在高分参考内容导入后的封面多版本测试。</p>
</div>
<div class="task-item">
<h4>海外 Shorts 试水项目</h4>
<h4>视频号试水项目</h4>
<p>视频积分占比偏高,建议先多做文案和封面验证,再放大视频试投。</p>
</div>
</div>