fix(monitor): 从界面上建的任务永远是小红书任务,平台从没被传上去
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s

现象:站在抖音页面上新建任务,任务跑到小红书列表里去了;界面上还写着「笔记」。

根因在前端:TaskCreatePayload 里**根本没有 platform 字段**,handleSubmit 拼的 payload
自然也不带它,而后端是 `payload.get("platform") or PLATFORM_XHS` —— 于是不管在哪个
平台标签下建任务,落下来的都是小红书任务。以前只支持小红书,两边都看不出问题。

* TaskCreatePayload 补上 platform(并在注释里写明为什么它是必填),handleSubmit 带上
  当前平台。
* 更新任务时不带 platform:平台创建后不可更改,带着会让「平台能改」看起来像真的。
* 三处写死的「笔记」改成按平台取措辞(能力矩阵的 target_hints.note_label):
  · 任务编辑器的类型选择项「笔记(批量监控指定内容)」
  · 「笔记模式下此项不生效」那句提示
  · 任务卡片上的类型徽章 —— 它按**任务自己的**平台取词,不是当前平台,因为卡片未必
    只出现在同平台的列表里
  抖音管它们叫「作品」,小红书叫「笔记」,写死一个对另一个就是错的。

测试 +1:后端这一半也守住 —— 建任务时显式给了平台,就必须落到那个平台,且不得出现在
另一个平台的列表里。前端那半边是 UI,测不了,但后端守住能挡住「给了不用」这类退化。

注意:这次是纯前端漏传,后端那个「缺省回退小红书」的行为本身没变(有测试断言它是
有意为之的兼容行为)。要彻底消灭这类静默错误,可以把缺省值去掉、让 platform 必填 ——
那会破坏 API 兼容性,目前没有任何别的调用方,需要的话说一声。
This commit is contained in:
2026-10-10 15:13:37 +08:00
parent e77e5e2f15
commit f3ea088c75
4 changed files with 49 additions and 5 deletions
@@ -109,7 +109,7 @@ export function TaskEditorDialog({ open, onOpenChange, task }: TaskEditorDialogP
const { data: settings } = useSettings()
// 示例链接和措辞都由服务端的能力矩阵给 —— 前端不自己判断平台,否则加一个平台
// 就要改这里一次,而且很容易漏。
const { capability } = useCurrentPlatform()
const { capability, platform } = useCurrentPlatform()
const hints = capability?.target_hints
const [name, setName] = useState('')
@@ -179,6 +179,9 @@ export function TaskEditorDialog({ open, onOpenChange, task }: TaskEditorDialogP
const handleSubmit = () => {
const payload: TaskCreatePayload = {
name: name.trim(),
// 当前平台。漏掉这一项,后端会退回小红书 —— 表现是「在抖音页面建的任务
// 跑到小红书列表里去了」,而且不报任何错。
platform,
mode,
interval_minutes: Number(intervalMinutes),
schedule_mode: scheduleMode,
@@ -199,7 +202,11 @@ export function TaskEditorDialog({ open, onOpenChange, task }: TaskEditorDialogP
const done = () => onOpenChange(false)
if (isEdit && task) {
updateTask.mutate({ id: task.id, payload }, { onSuccess: done })
// 平台创建后不可更改,更新请求里就不带它了 —— 带着会让「平台能被改」这件事
// 看起来像是真的。
const updatePayload: Partial<TaskCreatePayload> = { ...payload }
delete updatePayload.platform
updateTask.mutate({ id: task.id, payload: updatePayload }, { onSuccess: done })
} else {
createTask.mutate(payload, { onSuccess: done })
}
@@ -241,7 +248,7 @@ export function TaskEditorDialog({ open, onOpenChange, task }: TaskEditorDialogP
</SelectTrigger>
<SelectContent>
<SelectItem value="creator">博主(监控其作品)</SelectItem>
<SelectItem value="note">笔记(批量监控指定内容)</SelectItem>
<SelectItem value="note">{`${hints?.note_label ?? '笔记'}(批量监控指定内容)`}</SelectItem>
</SelectContent>
</Select>
{isEdit && (
@@ -432,7 +439,7 @@ export function TaskEditorDialog({ open, onOpenChange, task }: TaskEditorDialogP
</>
) : (
<p className="text-[10px] font-mono text-cyber-neon-orange">
笔记模式下此项不生效:你列出的每个链接都会被逐条抓取。
{hints?.note_label ?? '笔记'}模式下此项不生效:你列出的每个链接都会被逐条抓取。
</p>
)}
</div>