From: wang.yu Date: Tue, 18 Aug 2026 01:58:53 +0000 (+0800) Subject: feat: 新增「AI 智能补全」功能(站点基本属性) X-Git-Url: http://acesimba.cloud/gitweb/?a=commitdiff_plain;h=e8a77b8dc1dcb9c51a4ffd99f2c48b5cc5646976;p=StationBuilder.git feat: 新增「AI 智能补全」功能(站点基本属性) - 后端 db-sidecar 新增 POST /api/sites/:id/complete(流式 NDJSON 输出思考过程 + 以【补充描述】标记提取最终补充描述)与 GET .../complete-prompt(查看提示词) - 前端 Basic 页「填写建议」下方新增「AI 智能补全」面板:开始补全按钮 + 查看提示词 (复用提示词弹窗,新增 completePrompt 类型)+ 与「AI 生成工作流」同款流式控制台; 结果写入「补充要求」并走现有 autosave 持久化 - 设计文档 §5.3 与 11.1 同步更新 --- diff --git a/app/page.tsx b/app/page.tsx index 407b109..e3f9842 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState, type PointerEvent as ReactPointerEvent } from "react"; type PageKey = "login" | "projects" | "basic" | "assets" | "functions" | "generate" | "result" | "preview" | "domains" | "domainDetail" | "styleLibrary"; -type ModalKey = "" | "feedback" | "download" | "history" | "prompt"; +type ModalKey = "" | "feedback" | "download" | "history" | "prompt" | "completePrompt"; const meta: Record = { login:{label:"内部登录",icon:"◇",subtitle:"使用公司账号登录"}, @@ -200,7 +200,15 @@ export default function Home(){ setModal("prompt"); }catch(e:any){ notify("读取提示词失败: "+e.message); } }; - + const viewCompletePrompt=async()=>{ + if(!site?.id) { notify("请先创建或打开一个站点"); return; } + try{ + const qs=new URLSearchParams({name:site.name||"",domain:site.domain||"",description:site.description||""}).toString(); + const data:{prompt:string}=await fetchDb(`/sites/${site.id}/complete-prompt?${qs}`); + setPromptData({name:"AI 智能补全", text:data.prompt}); + setModal("completePrompt"); + }catch(e:any){ notify("读取提示词失败: "+e.message); } + }; const openFeedback=(cube:Cube)=>{ if(!cube.id){ notify("请先生成该页面再提出修改意见"); return; } setFeedbackCube(cube); @@ -431,7 +439,7 @@ export default function Home(){ {page==="domains"&&} {page==="domainDetail"&&} {page==="styleLibrary"&&} - {page==="basic"&&} + {page==="basic"&&} {page==="assets"&&} {page==="functions"&&} {page==="generate"&&} @@ -480,11 +488,40 @@ function Projects({view,setView,sites,loading,go,loadSite,notify,onDelete}:{view return <>
{[[String(counts.all),"全部项目"],[String(counts.draft),"草稿"],[String(counts.running),"生成中"],[String(counts.done),"生成完成"],[String(counts.partial),"部分失败"]].map(x=>
{x[0]}{x[1]}
)}
{selected.size>0 && }
{view==="table"?{sites.map(row=>)}
站点名称 ↕所属领域设备数量MU 页面Cube 页面状态最近修改操作
toggle(row.id)}/>{row.domain}{row.device_count}{row.mu_count}{row.cube_count}{row.status==="generated"?"生成完成":row.status==="partial"?"部分失败":row.status==="running"?"生成中":"草稿"}{row.updated_at}
:
{sites.map(row=>
go(row.status==="generated"?"result":"basic", row.id)}>
⬡{row.status==="generated"?"生成完成":row.status==="partial"?"部分失败":row.status==="running"?"生成中":"草稿"}

{row.name || "未命名站点"}

{row.domain}

{row.device_count} 设备{row.mu_count} MU{row.cube_count} Cube
更新于 {row.updated_at}
)}
}
共 {sites.length} 条
} -function Basic({site,domains,onChange,onAddDomain,onUpload,saving}:{site:SiteDetail|null;domains:string[];onChange:(p:Partial)=>void;onAddDomain:(n:string)=>void;onUpload:(f:File)=>void;saving:boolean}){ +function Basic({site,domains,onChange,onAddDomain,onUpload,saving,notify,onViewCompletePrompt}:{site:SiteDetail|null;domains:string[];onChange:(p:Partial)=>void;onAddDomain:(n:string)=>void;onUpload:(f:File)=>void;saving:boolean;notify:(m:string)=>void;onViewCompletePrompt:()=>void}){ const [newDomain,setNewDomain]=useState(""); const [domainInput,setDomainInput]=useState(site?.domain||""); const [showAdd,setShowAdd]=useState(false); useEffect(()=>{ if(site) setDomainInput(site.domain||""); },[site?.domain]); + const [completing,setCompleting]=useState(false); + const [completeLog,setCompleteLog]=useState(""); + const completeConsoleRef=useRef(null); + useEffect(()=>{ if(completeConsoleRef.current) completeConsoleRef.current.scrollTop=completeConsoleRef.current.scrollHeight; },[completeLog]); + const runComplete=async()=>{ + if(!site?.id || completing) return; + setCompleting(true); setCompleteLog(""); + const watchdog=setTimeout(()=>{ setCompleting(false); notify("AI 智能补全超时(>6 分钟),请重试"); }, 360000); + try{ + const res=await fetch(`/api/db/sites/${site.id}/complete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:site.name,domain:site.domain,description:site.description})}); + if(!res.ok||!res.body) throw new Error("HTTP "+res.status); + const reader=res.body.getReader(); const dec=new TextDecoder(); let buf=""; + for(;;){ + const {done,value}=await reader.read(); if(done) break; + buf+=dec.decode(value,{stream:true}); + const lines=buf.split("\n"); buf=lines.pop()||""; + for(const line of lines){ + if(!line.trim()) continue; + try{ + const ev=JSON.parse(line); + if(ev.log) setCompleteLog(prev=>prev+ev.log); + if(ev.result) onChange({supplement:ev.result}); + }catch{} + } + } + notify("AI 智能补全已完成,已写入补充描述"); + }catch(e:any){ notify("AI 智能补全失败:"+(e?.message||e)); } + finally{ clearTimeout(watchdog); setCompleting(false); } + }; if(!site) return
加载中…
; const nameTooLong = countChars(site.name)>20; const domainTooLong = newDomain.length>6; @@ -511,7 +548,18 @@ function Basic({site,domains,onChange,onAddDomain,onUpload,saving}:{site:SiteDet {site.files.length>0&&
    {site.files.map(f=>
  • {f.filename} ({(f.size/1024).toFixed(1)} KB)
  • )}
} -
  • 站点主要承担什么业务?
  • 哪些设备最重要?
  • 管理人员最关注哪些指标?
  • 希望首页首先看到什么?
{saving&&
正在保存…
}
; +
+
  • 站点主要承担什么业务?
  • 哪些设备最重要?
  • 管理人员最关注哪些指标?
  • 希望首页首先看到什么?
+ +

根据上方「站点名称 / 所属领域 / 站点基本情况描述」,由 AI 分析并自动补全「补充要求」。

+
+ + +
+ {(completing||completeLog)&&
AI 智能补全
{completeLog||"(等待 AI 分析…)"}
} +
+ {saving&&
正在保存…
} +
; } function Assets({site,onChange,saving}:{site:SiteDetail|null;onChange:(assets:Asset[])=>void;saving:boolean}){ @@ -925,10 +973,10 @@ function Modal({type,close,notify,promptData,feedbackCube,refineCube,refining,re const [feedbackText,setFeedbackText]=useState(""); const refineConsoleRef=useRef(null); useEffect(()=>{ if(refineConsoleRef.current) refineConsoleRef.current.scrollTop = refineConsoleRef.current.scrollHeight; }, [refineLog]); - const title={feedback:`提出修改意见 · ${feedbackCube?.name||""}`,download:"下载站点交付物",history:"版本历史",prompt:`生成提示词 · ${promptData?.name||""}`}[type]; + const title={feedback:`提出修改意见 · ${feedbackCube?.name||""}`,download:"下载站点交付物",history:"版本历史",prompt:`生成提示词 · ${promptData?.name||""}`,completePrompt:"AI 智能补全提示词"}[type]; const submitFeedback=()=>{ if(!feedbackCube){ notify("未选择目标 Cube 页面,请关闭后重试"); close(); return; } if(!refineCube){ notify("反馈功能未正确初始化"); return; } refineCube(feedbackCube, feedbackText); }; - return
e.stopPropagation()}>

{title}

{type==="feedback"&&<>
系统已识别本次修改范围(仅针对「{feedbackCube?.name}」页面)