/** * 会话与线索 API(Phase 3 Task 3 骨架;Task 5 实装调用函数并按实际响应修正类型) * * 端点与响应事实源:app/platform/routes/data_routes.py * - 列表:{total, page, page_size, items},行含 preview/intent_level/contact_info/ * email_sent/message_count/country/site 等;筛选 intent 白名单(interested/ * not_interested/pending,非法 400)/site 精确/client_info["site"]/from-to 闭区间 * (日期-only 的 to 含当日全天) * - 详情:扁平结构(元数据 + evaluation/profile/messages 三块),消息行字段为 * time(非 created_at);profile.chips 为 raw_info 去 _ 前缀键 * - 删除:{ok: true};不存在 404(级联消息/画像/评估/推送日志) * - push-logs:列表不回大 payload(load_only 排除 request_payload),带 * payload_size 服务端长度标记;status 白名单 pending/success/failed/skipped */ import { http } from './client' /** 意向层级(Evaluation.intent_level 枚举;列表筛选白名单同值) */ export type IntentLevel = 'interested' | 'not_interested' | 'pending' /** 推送状态(LeadPushLog.status;筛选白名单同值) */ export type PushLogStatus = 'pending' | 'success' | 'failed' | 'skipped' /** 联系方式(评估产出,留资三选一) */ export interface ContactInfo { email?: string | null whatsapp?: string | null phone?: string | null } /** 会话列表行(GET /api/platform/tenants/{slug}/conversations) */ export interface ConversationListItem { id: string session_id: string status: string source: string site: string | null ip: string device: string country: string | null intent_level: IntentLevel | null reasoning: string | null contact_info: ContactInfo | null email_sent: boolean message_count: number preview: string created_at: string | null } /** 会话列表查询参数(intent 白名单校验在后端;from/to 为闭区间日期 YYYY-MM-DD) */ export interface ConversationListParams { intent?: IntentLevel site?: string from?: string to?: string page?: number page_size?: number } /** 会话列表响应 */ export interface ConversationListResponse { total: number page: number page_size: number items: ConversationListItem[] } /** 会话详情消息行(时间升序;字段为 time) */ export interface ConversationMessage { role: 'user' | 'assistant' | 'system' | string content: string time: string | null } /** 评估块(详情内嵌,未评估为 null) */ export interface ConversationEvaluation { intent_level: IntentLevel | null reasoning: string | null contact_info: ContactInfo | null email_sent: boolean correction_count: number | null evaluated_at: string | null } /** 会话详情响应(GET .../conversations/{convId}——扁平,与列表行不同构) */ export interface ConversationDetail { id: string session_id: string status: string source: string client_info: Record site: string | null ip: string device: string country: string | null created_at: string | null updated_at: string | null evaluation: ConversationEvaluation | null profile: { chips: Record summary: string | null } | null messages: ConversationMessage[] } /** 推送日志行(GET .../push-logs——无 request_payload,仅 payload_size 长度标记) */ export interface PushLogItem { id: string evaluation_id: string conversation_id: string push_type: string status: PushLogStatus | string attempts: number outcome: string | null response_status: number | null error_message: string | null payload_size: number | null created_at: string | null updated_at: string | null } /** 推送日志查询参数(status 白名单校验在后端) */ export interface PushLogParams { status?: PushLogStatus conversation_id?: string page?: number page_size?: number } /** 推送日志响应 */ export interface PushLogResponse { total: number page: number page_size: number items: PushLogItem[] } /** 会话与线索端点 */ export const CONVERSATION_ENDPOINTS = { list: (slug: string) => `/api/platform/tenants/${slug}/conversations`, detail: (slug: string, convId: string) => `/api/platform/tenants/${slug}/conversations/${convId}`, remove: (slug: string, convId: string) => `/api/platform/tenants/${slug}/conversations/${convId}`, pushLogs: (slug: string) => `/api/platform/tenants/${slug}/push-logs` } as const // ---- 展示映射(枚举值事实源 data_routes.py INTENTS/PUSH_STATUSES 与 models.py) ---- /** 意向筛选/展示选项 */ export const INTENT_OPTIONS: Array<{ value: IntentLevel; label: string }> = [ { value: 'interested', label: '有意向' }, { value: 'not_interested', label: '无意向' }, { value: 'pending', label: '待定' } ] /** 意向展示文案(未知值回退原样) */ export function intentLabel(level: string | null | undefined): string { if (!level) return '未评估' return INTENT_OPTIONS.find((item) => item.value === level)?.label ?? level } /** 推送状态筛选/展示选项 */ export const PUSH_STATUS_OPTIONS: Array<{ value: PushLogStatus; label: string }> = [ { value: 'pending', label: '待推送' }, { value: 'success', label: '成功' }, { value: 'failed', label: '失败' }, { value: 'skipped', label: '跳过' } ] /** 推送状态展示文案 */ export function pushStatusLabel(status: string | null | undefined): string { if (!status) return '—' return PUSH_STATUS_OPTIONS.find((item) => item.value === status)?.label ?? status } /** 推送类型展示文案(LeadPushLog.push_type:lead/returning/correction) */ export function pushTypeLabel(type: string | null | undefined): string { const labels: Record = { lead: '新线索', returning: '回访', correction: '更正' } if (!type) return '—' return labels[type] ?? type } /** 会话状态展示文案(ConversationStatus) */ export function conversationStatusLabel(status: string | null | undefined): string { const labels: Record = { active: '进行中', completed: '已完成', abandoned: '已放弃' } if (!status) return '—' return labels[status] ?? status } /** 会话来源展示文案(ConversationSource) */ export function conversationSourceLabel(source: string | null | undefined): string { const labels: Record = { standalone: '独立站', embedded: '内嵌页', widget: '挂件', app: '应用' } if (!source) return '—' return labels[source] ?? source } // ---- 调用函数 ------------------------------------------------------------------- /** 会话列表(分页 + intent/site/日期区间筛选) */ export function fetchConversations( slug: string, params?: ConversationListParams ): Promise { return http.get(CONVERSATION_ENDPOINTS.list(slug), { params }) } /** 会话详情(元数据 + 画像 chips + 评估 + 消息全量) */ export function fetchConversationDetail( slug: string, convId: string ): Promise { return http.get(CONVERSATION_ENDPOINTS.detail(slug, convId)) } /** 删除会话(级联消息/画像/评估/推送日志;不存在 404) */ export function deleteConversation( slug: string, convId: string ): Promise<{ ok: boolean }> { return http.del<{ ok: boolean }>(CONVERSATION_ENDPOINTS.remove(slug, convId)) } /** 推送日志列表(status/conversation_id 筛选 + 分页;不回大 payload) */ export function fetchPushLogs(slug: string, params?: PushLogParams): Promise { return http.get(CONVERSATION_ENDPOINTS.pushLogs(slug), { params }) }