feat(v2): 完善配置中心与可替换轨迹质检并联动预审依据

This commit is contained in:
2026-10-01 17:13:02 +08:00
parent 1adbe16cb3
commit e604d177cb
42 changed files with 1285 additions and 83 deletions
@@ -20,7 +20,7 @@ export default function BusinessAssistant(){
const [input,setInput]=useState(""),[busy,setBusy]=useState(false),[error,setError]=useState("");
const [messages,setMessages]=useState<Message[]>([{id:"hello",side:"assistant",text:"你好,我是兴邦对公业务助手。选择项目后,你可以直接告诉我查状态、发起AI预审、生成报告或补充材料。"}]);
const role=identity?.role||"manager",project=projects.find(p=>p.id===projectId);
const quick=useMemo(()=>role==="reviewer"?["查看项目状态","发起独立评审","生成评审报告"]:role==="admin"?["查看项目状态"]:["查看项目状态","发起AI预审","生成预审报告","提交正式评审"],[role]);
const quick=useMemo(()=>role==="reviewer"?["查看项目状态","发起独立评审","生成评审报告"]:role==="admin"?["查看项目状态"]:["查看项目状态","我有几个 Skills?","哪些金融相关 Skills?","发起AI预审","生成预审报告"],[role]);
async function load(){
setError("");
@@ -32,7 +32,7 @@ export default function BusinessAssistant(){
const message=text.trim();if(!message||!projectId||busy)return;
if(message.includes("提交")&&message.includes("评审")&&!window.confirm(`确认将 ${projectId} 的AI预审报告提交正式评审?提交后保留当前版本。`))return;
setMessages(old=>[...old,{id:newRequestId(),side:"user",text:message}]);setInput("");setBusy(true);setError("");
try{const response=await fetch(`${ROOT}/commands`,{method:"POST",headers:{...headers(),"Idempotency-Key":newRequestId()},body:JSON.stringify({project_id:projectId,message})});const body=await response.json();if(!response.ok)throw Error(body.detail||"业务指令执行失败");setMessages(old=>[...old,{id:newRequestId(),side:"assistant",text:body.message,url:body.url,objectId:body.object_id}]);await load();}
try{const catalogQuery=/skill|rules?|技能|规则|数据卡|模板/i.test(message);const response=await fetch(`${ROOT}/${catalogQuery?"library/inventory":"commands"}`,{method:"POST",headers:{...headers(),"Idempotency-Key":newRequestId()},body:JSON.stringify({project_id:projectId,message})});const body=await response.json();if(!response.ok)throw Error(body.detail||"业务指令执行失败");setMessages(old=>[...old,{id:newRequestId(),side:"assistant",text:body.message,url:body.url,objectId:body.object_id}]);await load();}
catch(e:any){setError(e.message);setMessages(old=>[...old,{id:newRequestId(),side:"assistant",text:`未执行:${e.message}`}]);}
finally{setBusy(false)}
}
@@ -44,7 +44,7 @@ export default function BusinessAssistant(){
finally{setBusy(false)}
}
function submit(event:FormEvent){event.preventDefault();send(input)}
const conversation=<div className="ba-chat"><div className="ba-messages">{messages.map(message=><article key={message.id} className={message.side}><div>{message.side==="assistant"&&<Bot size={16}/>}<p>{message.text}</p>{message.side==="user"&&<span className="ba-user-icon" aria-label="本人"><UserRound size={17}/></span>}</div>{message.objectId&&<small>操作凭证 · {message.objectId}</small>}{message.url&&<a href={message.url}>查看项目中的结果<ArrowUpRight size={14}/></a>}</article>)}{busy&&<article className="assistant pending"><div><Bot size={16}/><p>正在执行并生成可追溯记录…</p></div></article>}</div>
const conversation=<div className="ba-chat"><div className="ba-messages">{messages.map(message=><article key={message.id} className={message.side}><div>{message.side==="assistant"&&<Bot size={16}/>}<p style={{whiteSpace:"pre-line"}}>{message.text}</p>{message.side==="user"&&<span className="ba-user-icon" aria-label="本人"><UserRound size={17}/></span>}</div>{message.objectId&&<small>操作凭证 · {message.objectId}</small>}{message.url&&<a href={message.url}>查看项目中的结果<ArrowUpRight size={14}/></a>}</article>)}{busy&&<article className="assistant pending"><div><Bot size={16}/><p>正在执行并生成可追溯记录…</p></div></article>}</div>
{error&&<div role="alert" className="ba-error">{error}</div>}
<form onSubmit={submit}><label className="ba-attach" title="补充项目材料"><Paperclip size={18}/><input aria-label="补充项目材料" type="file" accept=".txt,.csv,.docx,.xlsx,.pdf,.png,.jpg,.jpeg" onChange={attach}/></label><input aria-label="业务指令" value={input} onChange={e=>setInput(e.target.value)} placeholder={`例如:帮我做一次 ${projectId||"当前项目"} 风险研判`}/><button aria-label="发送业务指令" disabled={busy||!input.trim()||!projectId}><Send size={18}/></button></form><footer><FilePlus2 size={13}/>当前身份只会调用本项目授权的 Skills、规则和业务工具,并保留操作凭证。</footer>
</div>;