const [view,setView]=useState<"table"|"card">("table");
const [siteEditSection,setSiteEditSection]=useState<SiteEditSection>("basic");
const [assetConfigMode,setAssetConfigMode]=useState<"quick"|"manual">("quick");
- const [pageConfigTab,setPageConfigTab]=useState<"ops"|"dashboard"|"report"|"twin">("ops");
- const PAGE_CONFIG_LABEL:Record<string,string>={ops:"设备运维",dashboard:"仪表板",report:"报表",twin:"数字孪生场景"};
+ const [pageConfigTab,setPageConfigTab]=useState<"ops"|"dashboard"|"twin">("ops");
+ const PAGE_CONFIG_LABEL:Record<string,string>={ops:"设备运维",dashboard:"仪表板",twin:"数字孪生场景"};
const [functionTab,setFunctionTab]=useState<"mu"|"cube"|"menu">("mu");
const [previewTab,setPreviewTab]=useState<"info"|"json"|"feedback">("info");
const [feedbackCube,setFeedbackCube]=useState<Cube|null>(null);
<div className="asset-config-tabs" role="tablist" aria-label="页面配置">
<button role="tab" aria-selected={pageConfigTab==="ops"} className={pageConfigTab==="ops"?"active":""} onClick={()=>setPageConfigTab("ops")}><span>设备运维</span><small>设备运行维护相关配置</small></button>
<button role="tab" aria-selected={pageConfigTab==="dashboard"} className={pageConfigTab==="dashboard"?"active":""} onClick={()=>setPageConfigTab("dashboard")}><span>仪表板</span><small>可视化仪表板配置</small></button>
- <button role="tab" aria-selected={pageConfigTab==="report"} className={pageConfigTab==="report"?"active":""} onClick={()=>setPageConfigTab("report")}><span>报表</span><small>报表配置</small></button>
<button role="tab" aria-selected={pageConfigTab==="twin"} className={pageConfigTab==="twin"?"active":""} onClick={()=>setPageConfigTab("twin")}><span>数字孪生场景</span><small>数字孪生场景配置</small></button>
</div>
- <Panel title={PAGE_CONFIG_LABEL[pageConfigTab]}><div className="muted">内容待补充</div></Panel>
+ {pageConfigTab==="ops"
+ ? <Panel title={PAGE_CONFIG_LABEL.ops}>{/* MU 标准页面表格,移自功能与菜单,默认全选中 */}
+ {(()=>{
+ const opLeaves = buildMuLeaves(muTree);
+ const opGrouped = (()=>{ const map=new Map<string,{parentMenu:string,items:typeof opLeaves}>(); for(const l of opLeaves){ if(!map.has(l.parentMenu)) map.set(l.parentMenu,{parentMenu:l.parentMenu,items:[]}); map.get(l.parentMenu)!.items.push(l); } return Array.from(map.values()); })();
+ const opAllKeys = opLeaves.map(l=>l.key);
+ const opSelected = site?.mu || [];
+ const opEff = opSelected.length ? opSelected : opAllKeys;
+ const opToggle=(key:string)=>{ const base=opSelected.length?opSelected:opAllKeys; saveMu(base.includes(key)?base.filter(k=>k!==key):[...base,key]); };
+ return <div className="mu-tree">{opGrouped.map(g=><div key={g.parentMenu} className="mu-group"><b>{g.parentMenu}</b><div className="mu-items">{g.items.map(item=><label key={item.key} className={item.disabled?"disabled":""}><input type="checkbox" disabled={item.disabled} checked={opEff.includes(item.key)} onChange={()=>opToggle(item.key)}/><span>{item.label}</span></label>)}</div></div>)}</div>;
+ })()}
+ </Panel>
+ : <Panel title={PAGE_CONFIG_LABEL[pageConfigTab]}><div className="muted">内容待补充</div></Panel>}
</div>}
{page==="functions"&&<Functions site={site} muTree={muTree} onMuChange={saveMu} onSiteChange={setSite} pageStyles={pageStyles} notify={notify} onViewCompletePrompt={viewCompleteCubesPrompt}/>}
{page==="siteEdit"&&siteEditSection==="functions"&&<Functions site={site} muTree={muTree} onMuChange={saveMu} onSiteChange={setSite} pageStyles={pageStyles} notify={notify} onViewCompletePrompt={viewCompleteCubesPrompt}/>}
}
function Functions({site,muTree,onMuChange,onSiteChange,pageStyles,notify,onViewCompletePrompt}:{site:SiteDetail|null;muTree:MuNode[];onMuChange:(s:string[])=>void;onSiteChange:(s:SiteDetail)=>void;pageStyles:PageStyle[];notify:(m:string)=>void;onViewCompletePrompt:()=>void}){
- const [tab,setTab]=useState<"mu"|"cube"|"menu">("mu");
+ const [tab,setTab]=useState<"mu"|"cube"|"menu">("cube");
const leaves = useMemo(()=>buildMuLeaves(muTree),[muTree]);
- const grouped = useMemo(()=>{
- const map = new Map<string,{parentMenu:string, items:typeof leaves}>();
- for(const leaf of leaves){
- if(!map.has(leaf.parentMenu)) map.set(leaf.parentMenu, {parentMenu:leaf.parentMenu, items:[]});
- map.get(leaf.parentMenu)!.items.push(leaf);
- }
- return Array.from(map.values());
- },[leaves]);
const allMuKeys = useMemo(()=>leaves.map(l=>l.key),[leaves]);
const selectedMu = site?.mu || [];
// 默认全选中:site.mu 为空时按全部叶子键显示,首次勾选才落地保存
const effSelected = selectedMu.length ? selectedMu : allMuKeys;
if(!site) return <Panel><div className="empty-state">加载中…</div></Panel>;
- const toggleMu=(key:string)=>{
- const base = selectedMu.length ? selectedMu : allMuKeys;
- onMuChange(base.includes(key)? base.filter(k=>k!==key) : [...base, key]);
- };
const updateCube=(idx:number, patch:Partial<Cube>)=>{
const next = site.cubes.map((c,i)=>i===idx?{...c,...patch}:c);
onSiteChange({...site, cubes:next});
finally{ clearTimeout(watchdog); setCompleting(false); }
};
- return <Panel><div className="tabs"><button className={tab==="cube"?"active":""} onClick={()=>setTab("cube")}>领域扩展页面 <i>{site.cubes.length}</i></button><button className={tab==="mu"?"active":""} onClick={()=>setTab("mu")}>MU 标准页面 <i>{effSelected.length}</i></button><button className={tab==="menu"?"active":""} onClick={()=>setTab("menu")}>菜单结构</button></div>
- {/* MU 标准页面:树状上下结构,仅保留勾选框,默认全选中 */}
- {tab==="mu"&&<div className="mu-tree">{grouped.map(g=><div key={g.parentMenu} className="mu-group"><b>{g.parentMenu}</b><div className="mu-items">{g.items.map(item=><label key={item.key} className={item.disabled?"disabled":""}><input type="checkbox" disabled={item.disabled} checked={effSelected.includes(item.key)} onChange={()=>toggleMu(item.key)}/><span>{item.label}</span></label>)}</div></div>)}</div>}
+ return <Panel><div className="tabs"><button className={tab==="cube"?"active":""} onClick={()=>setTab("cube")}>领域扩展页面 <i>{site.cubes.length}</i></button><button className={tab==="menu"?"active":""} onClick={()=>setTab("menu")}>菜单结构</button></div>
{/* Cube 扩展页面:左右两栏,右栏为填写建议 + AI 智能补全 */}
{tab==="cube"&&<div className="two-column">
<div>
];
const MU_TREE = [
- {
- key: "设备监控",
- tabs: ["设备总览", "设备详情"],
- },
- {
- key: "数据分析",
- tabs: ["数据分析", "报表分析", "用量分析"],
- },
- {
- key: "智能控制",
- tabs: ["远程控制计划", "执行记录", "控制模板"],
- },
+ { key: "设备监控", tabs: ["设备总览", "设备详情", "区域监控", "视频监控"] },
+ { key: "数据分析", tabs: ["数据分析", "报表分析", "用量分析"] },
+ { key: "智能控制", tabs: ["远程控制计划", "执行记录", "控制模板"] },
+ { key: "位置设定", tabs: ["位置设定"] },
+ { key: "区域监控", tabs: ["区域监控"] },
+ { key: "综合事务维修", tabs: ["综合事务维修"] },
+ { key: "设备维修", tabs: ["设备维修"] },
+ { key: "外委维修", tabs: ["外委维修"] },
+ { key: "保养工单", tabs: ["保养工单"] },
+ { key: "保养计划", tabs: ["保养计划"] },
+ { key: "保养标准", tabs: ["保养标准"] },
+ { key: "点检工单", tabs: ["点检工单"] },
+ { key: "异常工单", tabs: ["异常工单"] },
+ { key: "点检计划", tabs: ["点检计划"] },
+ { key: "点检标准", tabs: ["点检标准"] },
+ { key: "台账列表", tabs: ["台账列表"] },
+ { key: "台账模板", tabs: ["台账模板"] },
+ { key: "设备类型", tabs: ["设备类型"] },
+ { key: "定时提醒日志", tabs: ["定时提醒日志"] },
+ { key: "备件列表", tabs: ["备件列表"] },
+ { key: "备件入库", tabs: ["备件入库"] },
+ { key: "备件出库", tabs: ["备件出库"] },
+ { key: "备件盘点", tabs: ["备件盘点"] },
+ { key: "仓库管理", tabs: ["仓库管理"] },
+ { key: "库位管理", tabs: ["库位管理"] },
+ { key: "出入库类型", tabs: ["出入库类型"] },
+ { key: "工单中心", tabs: ["工单中心"] },
+ { key: "表单设计", tabs: ["表单设计"] },
+ { key: "流程设计", tabs: ["流程设计"] },
+ { key: "系统设置", tabs: ["自定义应用", "设备类型"] },
+ { key: "台账设置", tabs: ["台账设置"] },
+ { key: "备件设置", tabs: ["备件设置"] },
+ { key: "工单管理设置", tabs: ["综合事务分类", "故障分类", "多级告警", "流程表单配置"] },
+ { key: "设备监控设置", tabs: ["区域监控设置"] },
];
const DASHBOARD_SPEC = `