fix: retain stock identities in research and AI task lists
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import {StockIdentity} from "./StockIdentity"
|
||||
import {useEffect,useState} from "react"
|
||||
import {request,ApiError} from "@/lib/auth"
|
||||
import {Button} from "@/components/ui/button"
|
||||
@@ -5,7 +6,7 @@ import {Badge} from "@/components/ui/badge"
|
||||
import {Card,CardHeader,CardTitle,CardContent,CardDescription} from "@/components/ui/card"
|
||||
type Policy={enabled:boolean;auto_publish:boolean;version:number}
|
||||
type Conclusion={symbol:string;decision:string;summary:string;risks:string;missing_information:string[]}
|
||||
type Analysis={id:string;status:string;attempts:number;message:string;primary_model:string;review_model:string;analysis?:Conclusion;review?:Conclusion;updated_at:string}
|
||||
type Analysis={id:string;name:string;symbol:string;exchange:string;status:string;attempts:number;message:string;primary_model:string;review_model:string;analysis?:Conclusion;review?:Conclusion;updated_at:string}
|
||||
const states:Record<string,string>={RUNNING:"分析中",FAILED:"调用失败",APPROVED:"已通过 · 等待发布",REJECTED:"AI 未通过",PUBLISHED:"已自动发布",STALE:"版本或规则已失效"}
|
||||
export function AIReviewPanel({onSessionExpired}:{onSessionExpired:()=>void}){
|
||||
const [policy,setPolicy]=useState<Policy|null>(null),[results,setResults]=useState<Analysis[]>([]),[enabled,setEnabled]=useState(false),[auto,setAuto]=useState(false),[error,setError]=useState(""),[busy,setBusy]=useState(false),[notice,setNotice]=useState("")
|
||||
@@ -13,5 +14,5 @@ export function AIReviewPanel({onSessionExpired}:{onSessionExpired:()=>void}){
|
||||
useEffect(()=>{const c=new AbortController();request<Policy>("/api/admin/v1/ai-review-policy",{signal:c.signal}).then(p=>{setPolicy(p);setEnabled(p.enabled);setAuto(p.auto_publish)}).catch(e=>{if(!c.signal.aborted)failure(e)});const load=()=>request<Analysis[]>("/api/admin/v1/candidate-analyses",{signal:c.signal}).then(setResults).catch(e=>{if(!c.signal.aborted)failure(e)});void load();const timer=setInterval(()=>void load(),5000);return()=>{c.abort();clearInterval(timer)}},[onSessionExpired])
|
||||
async function save(){if(!policy)return;setBusy(true);setError("");try{const p=await request<Policy>("/api/admin/v1/ai-review-policy",{method:"PUT",body:JSON.stringify({enabled,auto_publish:auto,expected_version:policy.version})});setPolicy(p);setNotice("审核策略已保存,后台会处理待审核候选。")}catch(e){failure(e)}finally{setBusy(false)}}
|
||||
async function run(){setBusy(true);setError("");try{await request("/api/admin/v1/candidate-analyses/run",{method:"POST"});setNotice("已通知后台处理;结果自动刷新。")}catch(e){failure(e)}finally{setBusy(false)}}
|
||||
return <Card><CardHeader><CardTitle>AI 候选分析与自动审核</CardTitle><CardDescription>策略筛选 → 主模型分析 → 审核模型复核 → 服务端规则校验 → App 发布。仅限模拟研究;不会生成计划或成交。</CardDescription></CardHeader><CardContent className="space-y-5"><div className="flex flex-wrap gap-5"><label className="flex items-center gap-2 text-sm"><input type="checkbox" checked={enabled} disabled={busy||!policy} onChange={e=>setEnabled(e.target.checked)}/>启用 AI 分析与审核</label><label className="flex items-center gap-2 text-sm"><input type="checkbox" checked={auto} disabled={busy||!policy} onChange={e=>setAuto(e.target.checked)}/>审核与规则通过后自动发布</label></div><p className="text-sm text-muted-foreground">主模型和审核模型必须配置并启用。关闭自动发布时保留 AI 意见供人工复核;失败最多重试三次,候选过期不发布。</p><div className="flex gap-3"><Button disabled={busy||!policy} onClick={()=>void save()}>保存审核策略</Button><Button variant="outline" disabled={busy||!policy?.enabled} onClick={()=>void run()}>立即处理待审核候选</Button></div>{notice&&<p role="status" className="text-sm">{notice}</p>}{error&&<p role="alert" className="text-sm text-destructive">{error}</p>}<div className="space-y-3">{results.length===0&&<p className="text-sm text-muted-foreground">暂无 AI 任务。启用后自动处理有效待审核候选。</p>}{results.map(a=><div key={a.id} className="rounded-xl border p-4 space-y-2"><div className="flex justify-between gap-3"><strong>{a.analysis?.symbol??"候选分析任务"}</strong><Badge variant="outline">{states[a.status]??a.status}</Badge></div><p className="text-sm">{a.message||"正在调用模型…"}</p>{a.analysis&&<><p className="text-sm leading-6">分析:{a.analysis.summary}</p><p className="text-sm text-muted-foreground">风险:{a.analysis.risks}</p></>}{a.review&&<p className="text-sm leading-6">复核:{a.review.summary}</p>}<p className="text-xs text-muted-foreground">{a.primary_model||"待调用"} / {a.review_model||"待调用"} · 尝试 {a.attempts} · {new Date(a.updated_at).toLocaleString("zh-CN")}</p></div>)}</div></CardContent></Card>
|
||||
return <Card><CardHeader><CardTitle>AI 候选分析与自动审核</CardTitle><CardDescription>策略筛选 → 主模型分析 → 审核模型复核 → 服务端规则校验 → App 发布。仅限模拟研究;不会生成计划或成交。</CardDescription></CardHeader><CardContent className="space-y-5"><div className="flex flex-wrap gap-5"><label className="flex items-center gap-2 text-sm"><input type="checkbox" checked={enabled} disabled={busy||!policy} onChange={e=>setEnabled(e.target.checked)}/>启用 AI 分析与审核</label><label className="flex items-center gap-2 text-sm"><input type="checkbox" checked={auto} disabled={busy||!policy} onChange={e=>setAuto(e.target.checked)}/>审核与规则通过后自动发布</label></div><p className="text-sm text-muted-foreground">主模型和审核模型必须配置并启用。关闭自动发布时保留 AI 意见供人工复核;失败最多重试三次,候选过期不发布。</p><div className="flex gap-3"><Button disabled={busy||!policy} onClick={()=>void save()}>保存审核策略</Button><Button variant="outline" disabled={busy||!policy?.enabled} onClick={()=>void run()}>立即处理待审核候选</Button></div>{notice&&<p role="status" className="text-sm">{notice}</p>}{error&&<p role="alert" className="text-sm text-destructive">{error}</p>}<div className="space-y-3">{results.length===0&&<p className="text-sm text-muted-foreground">暂无 AI 任务。启用后自动处理有效待审核候选。</p>}{results.map(a=><div key={a.id} className="rounded-xl border p-4 space-y-2"><div className="flex justify-between gap-3"><strong><StockIdentity name={a.name} symbol={a.symbol}/></strong><Badge variant="outline">{states[a.status]??a.status}</Badge></div><p className="text-sm">{a.message||"正在调用模型…"}</p>{a.analysis&&<><p className="text-sm leading-6">分析:{a.analysis.summary}</p><p className="text-sm text-muted-foreground">风险:{a.analysis.risks}</p></>}{a.review&&<p className="text-sm leading-6">复核:{a.review.summary}</p>}<p className="text-xs text-muted-foreground">{a.primary_model||"待调用"} / {a.review_model||"待调用"} · 尝试 {a.attempts} · {new Date(a.updated_at).toLocaleString("zh-CN")}</p></div>)}</div></CardContent></Card>
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user