import { Alert, Button, Card, Descriptions, Drawer, Form, Input, Select, Space, Table, Tag, Typography } from 'antd'; import { useEffect, useRef, useState } from 'react'; import { api, errorText } from '../api'; import type { BusinessBrief, BusinessConditions, PageResult } from '../types'; import { formatTime, LoadError, useResource } from './common'; export const briefFieldLabels: Record = { platform: '目标平台', service: '商品或服务', target_customer: '目标客户', search_terms: '搜索词', region: '服务地区', region_scope: '地区范围', exclude_service_promotions: '排除服务推广' }; const briefStatusLabels: Record = { draft: '待人工确认', needs_clarification: '需要补充条件', unsupported: '超出当前支持范围', failed: '解析未完成', confirmed: '条件已确认' }; export function RegionScope({ conditions }: { conditions: Pick }) { return <>{conditions.region_scope === 'specified' ? conditions.region : conditions.region_scope === 'unrestricted' ? '不限地区(已明确选择)' : '未设置,不推断全国'}; } export function BriefConditions({ brief }: { brief: BusinessBrief }) { return }, { key: 'exclude', label: '服务推广', children: brief.conditions.exclude_service_promotions === null ? '待确认' : brief.conditions.exclude_service_promotions ? '匹配时排除服务推广信号' : '不额外排除,仍独立判断自身需求' }, ]} />; } export function BusinessBriefPanel({ onUse }: { onUse: (brief: BusinessBrief) => void }) { const records = useResource>('/business/briefs'); const [open, setOpen] = useState(false); const [selected, setSelected] = useState(); const [requestText, setRequestText] = useState(''); const [error, setError] = useState(''); const [busy, setBusy] = useState(false); const [confirmForm] = Form.useForm(); const active = useRef(false), mounted = useRef(true); useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []); const scope = Form.useWatch('region_scope', confirmForm); function show(brief?: BusinessBrief) { setError(''); setSelected(brief); confirmForm.resetFields(); if (brief) { setRequestText(brief.request_text); confirmForm.setFieldsValue(brief.conditions); } setOpen(true); } async function parse() { if (active.current || !requestText.trim()) return; active.current = true; setBusy(true); setError(''); try { const result = await api.post('/business/briefs', { request_text: requestText.trim() }); if (!mounted.current) return; setSelected(result); confirmForm.resetFields(); confirmForm.setFieldsValue(result.conditions); await records.reload(); } catch (failure) { if (mounted.current) { setError(errorText(failure)); await records.reload(); } } finally { active.current = false; if (mounted.current) setBusy(false); } } async function confirm(values: BusinessConditions) { if (active.current || !selected || !['draft', 'needs_clarification'].includes(selected.status)) return; active.current = true; setBusy(true); setError(''); try { const result = await api.post(`/business/briefs/${selected.id}/confirm`, { ...values, search_terms: values.search_terms.map(value => value.trim()), region: values.region_scope === 'specified' ? values.region?.trim() || null : null }); if (!mounted.current) return; setSelected(result); await records.reload(); } catch (failure) { if (mounted.current) setError(errorText(failure)); } finally { active.current = false; if (mounted.current) setBusy(false); } } const canConfirm = selected && ['draft', 'needs_clarification'].includes(selected.status); return { setRequestText(''); show(); }}>输入商家需求}> 先说明你提供什么服务、要找谁和服务地区,解析后由你确认条件,再用于搜索和已读内容分析。 当前支持小红书装修服务样例;解析不会打开平台或执行关注、私信和评论。确认业务条件不等于已核实客户身份。 data-testid="business-brief-history" size="small" rowKey="id" loading={records.loading} dataSource={records.data?.items || []} pagination={{ pageSize: 3, showSizeChanger: false }} scroll={{ x: 620 }} locale={{ emptyText: '尚无商家需求,点击右上角输入。' }} columns={[ { title: '时间', key: 'created_at', render: (_, row) => formatTime(row.created_at) }, { title: '需求', key: 'request', render: (_, row) => {row.request_text} }, { title: '状态', key: 'status', render: (_, row) => {briefStatusLabels[row.status]} }, { title: '操作', key: 'view', render: (_, row) => {row.status === 'confirmed' && } }, ]} /> { if (!busy) setOpen(false); }} closable={{ 'aria-label': '关闭商家需求' }} size="min(800px, 100vw)" destroyOnHidden styles={{ body: { padding: 20, overflowWrap: 'anywhere' } }}>
例如:我是做装修服务的,想在小红书找准备装修的业主,服务杭州,排除装修公司推广。 setRequestText(event.target.value)} placeholder="说明商品或服务、目标客户、平台和地区;没有提供的条件会留待确认。" /> {error && } {selected &&
{briefStatusLabels[selected.status]}{formatTime(selected.created_at)} 本次原始需求:{selected.request_text} {selected.missing_fields.length > 0 && briefFieldLabels[field as keyof BusinessConditions] || field).join('、')} />} {selected.status === 'failed' && } {selected.status === 'unsupported' && } {selected.uncertainties.length > 0 &&
    {selected.uncertainties.map((value, index) =>
  • {value}
  • )}
} {selected.kind === 'parse' &&

解析字段与原文依据

{Object.entries(selected.field_evidence).map(([field, quotes]) => {briefFieldLabels[field as keyof BusinessConditions] || field}:{quotes.length ? quotes.map(quote => `「${quote}」`).join(';') : '原文未提供,不能自动补全'})}
} {canConfirm && form={confirmForm} layout="vertical" disabled={busy} onFinish={values => void confirm(values)} data-testid="business-brief-confirm-form">

人工核对并确认条件

确认会追加一条条件记录,保留原解析;所有确认字段记为维护者确认,不冒充模型原文依据。
}