323588c54d
Task 8(TDD):草稿包→表单/保存序列/warnings 分级纯函数 + POST/GET API 薄封装。事实源 app/platform/routes/site_import_routes.py(GET 五键 无 failed_phase——retry 对 failed 一律展示后端 409 兜底)与 generator.py build() 的 spec §4 草稿包形状。保存序列沉淀 spec §5 顺序语义(brand 的 GET 在头像上传之后)与 deflections_contact 池形态分派注记,Task 9 装配 消费。前端 vitest 188 → 201。 Co-Authored-By: Claude Code <noreply@anthropic.com>
78 lines
3.4 KiB
TypeScript
78 lines
3.4 KiB
TypeScript
/**
|
||
* site-import API(POST 启动 / GET 轮询)——Task 8;消费方
|
||
* site-import 视图(Task 9)。
|
||
*
|
||
* 端点事实源:app/platform/routes/site_import_routes.py
|
||
* (/api/platform/tenants/{slug}/site-import[/{task_id}],
|
||
* _tenant_guard 守租户——超管与租户管理员两角色可用)。
|
||
*
|
||
* 契约要点(Task 7 评审备忘):
|
||
* - POST 200(非 201)→ {task_id};body 单形态发送——新建 {url} /
|
||
* 复活 {retry: 'generate', task_id}(retry 形态后端忽略 url 字段);
|
||
* - 429(每租户 15 分钟 3 次频控)/ 409(并发上限·非 generate-failed
|
||
* 态复活)的 detail 已是白话文案——调用方原样展示,不二次翻译;
|
||
* - GET 五键 status/phase/pages/draft/error——**无 failed_phase**:前端
|
||
* retry 按钮对 failed 一律展示,能否复活由后端 409 兜底判定;
|
||
* - GET 404 = 任务不存在/已过期(终态语义——视图层 isTerminal404 消费)。
|
||
*
|
||
* 草稿包类型 SiteImportDraft 是 spec §4 的单一 TS 镜像,定义在视图
|
||
* model(type-only 反向引用,无运行时耦合——api 层不 import 视图代码)。
|
||
*/
|
||
import { http, type RequestOptions } from './client'
|
||
import type { SiteImportDraft } from '@/views/site-import/model'
|
||
|
||
/** 任务状态(app/platform/site_import/task.py TaskState 镜像) */
|
||
export type SiteImportStatus = 'pending' | 'crawling' | 'generating' | 'done' | 'failed'
|
||
|
||
/** GET 轮询响应五键(spec §4;后端恒返五键——非 done 时 draft 为 null) */
|
||
export interface SiteImportTaskResponse {
|
||
status: SiteImportStatus
|
||
/** 运行中阶段('crawling' | 'generating';非运行态 null) */
|
||
phase: string | null
|
||
/** 已抓页数(运行中递增;BFS 总数不可知——展示「第 N 页」不展示 M) */
|
||
pages: number
|
||
/** 草稿包(仅 status=done 非 null) */
|
||
draft: SiteImportDraft | null
|
||
/** 白话失败原因(仅 status=failed 非 null) */
|
||
error: string | null
|
||
}
|
||
|
||
/** POST body 单形态:新建 {url} / 复活 {retry, task_id}(后端对 retry
|
||
* 形态忽略 url——前端按用途二选一发送,不带冗余键) */
|
||
export type StartSiteImportBody = { url: string } | { retry: 'generate'; task_id: string }
|
||
|
||
/** POST 启动响应 */
|
||
export interface StartSiteImportResponse {
|
||
task_id: string
|
||
}
|
||
|
||
/** 启动/复活导入任务(POST /api/platform/tenants/{slug}/site-import)。
|
||
* 新建传 {url}(http(s) 公网地址——内网/非法地址 400);复活传
|
||
* {retry: 'generate', task_id}(同 task_id 只重跑生成步,复用已抓文本)。
|
||
* 429/409/404 经既有 ApiError 抛(detail 为白话文案)。 */
|
||
export function startSiteImport(
|
||
slug: string,
|
||
body: StartSiteImportBody,
|
||
config?: RequestOptions
|
||
): Promise<StartSiteImportResponse> {
|
||
return http.post<StartSiteImportResponse>(
|
||
`/api/platform/tenants/${slug}/site-import`,
|
||
body,
|
||
config
|
||
)
|
||
}
|
||
|
||
/** 轮询任务状态(GET /api/platform/tenants/{slug}/site-import/{task_id})。
|
||
* 3s 间隔;7.5 分钟窗口外自动停(> 服务端 7 分钟总超时)。404 = 过期
|
||
* 终态(isTerminal404)——跨租户持他人 task_id 同为 404。 */
|
||
export function getSiteImportTask(
|
||
slug: string,
|
||
taskId: string,
|
||
config?: RequestOptions
|
||
): Promise<SiteImportTaskResponse> {
|
||
return http.get<SiteImportTaskResponse>(
|
||
`/api/platform/tenants/${slug}/site-import/${taskId}`,
|
||
config
|
||
)
|
||
}
|