80 lines
4.1 KiB
TypeScript
80 lines
4.1 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
||
import { Page } from "../lib/types";
|
||
import { fetchDashboardSummary, DashboardSummary } from "../lib/api";
|
||
|
||
interface Props { onNavigate: (page: Page) => void; }
|
||
|
||
export function HomePage({ onNavigate }: Props) {
|
||
const [dash, setDash] = useState<DashboardSummary | null>(null);
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
fetchDashboardSummary().then(d => { setDash(d); setLoading(false); }).catch(() => setLoading(false));
|
||
}, []);
|
||
|
||
if (loading) return <div><h1 className="page-title">🌊 欢迎回家</h1><p style={{color:"#999"}}>加载中...</p></div>;
|
||
if (!dash) return <div><h1 className="page-title">🌊 欢迎回家</h1><p style={{color:"#999"}}>无法连接频道仓库</p></div>;
|
||
|
||
return <div>
|
||
<h1 className="page-title">🌊 欢迎回到你的初始化频道</h1>
|
||
|
||
<div className="card" style={{background: "var(--bg2)"}}>
|
||
<div style={{display:"flex",alignItems:"center",gap:"0.75rem",marginBottom:"0.75rem"}}>
|
||
<span style={{width:10,height:10,borderRadius:"50%",background:dash.repoConnected?"var(--su)":"var(--da)",display:"inline-block"}}/>
|
||
<span style={{fontWeight:600}}>频道管家 · {dash.stewardName}</span>
|
||
<span style={{fontSize:"0.75rem",color:"var(--t2)"}}>{dash.stewardId} · {dash.stewardStatus}</span>
|
||
</div>
|
||
<div style={{fontSize:"0.85rem",color:"var(--t2)"}}>
|
||
上次同步:{dash.lastSync} · 永久记忆:{dash.hasMemoryPackage ? "✅ 已启用" : "⚠️ 未检测到"} · 仓库:{dash.repoConnected ? "✅ 已连接" : "❌ 未连接"}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="stats" style={{gridTemplateColumns:"repeat(3,1fr)"}}>
|
||
<div className="stat-card">
|
||
<div className="stat-value">{dash.receiptCount}</div>
|
||
<div className="stat-label">全部回执</div>
|
||
</div>
|
||
<div className="stat-card">
|
||
<div className="stat-value">{dash.completedWorkOrders}</div>
|
||
<div className="stat-label">已完成</div>
|
||
</div>
|
||
<div className="stat-card">
|
||
<div className="stat-value">{dash.activeWorkOrders}</div>
|
||
<div className="stat-label">进行中</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h2 style={{fontSize:"1.1rem",marginBottom:"0.75rem"}}>快捷入口</h2>
|
||
<div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:"0.75rem",marginBottom:"1.5rem"}}>
|
||
<div className="card" style={{cursor:"pointer"}} onClick={() => onNavigate("plan")}>
|
||
<div style={{fontSize:"1.2rem",marginBottom:"0.25rem"}}>📋</div>
|
||
<div style={{fontWeight:600,fontSize:"0.95rem"}}>工单面板</div>
|
||
<div style={{fontSize:"0.8rem",color:"var(--t2)"}}>创建 · 追踪 · 闭环</div>
|
||
</div>
|
||
<div className="card" style={{cursor:"pointer"}} onClick={() => onNavigate("settings")}>
|
||
<div style={{fontSize:"1.2rem",marginBottom:"0.25rem"}}>📦</div>
|
||
<div style={{fontWeight:600,fontSize:"0.95rem"}}>模块商店</div>
|
||
<div style={{fontSize:"0.8rem",color:"var(--t2)"}}>浏览 · 安装 · 管理</div>
|
||
</div>
|
||
<div className="card" style={{cursor:"pointer"}} onClick={() => onNavigate("settings")}>
|
||
<div style={{fontSize:"1.2rem",marginBottom:"0.25rem"}}>🧠</div>
|
||
<div style={{fontWeight:600,fontSize:"0.95rem"}}>记忆健康</div>
|
||
<div style={{fontSize:"0.8rem",color:"var(--t2)"}}>模型可换 · 记忆不丢</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h2 style={{fontSize:"1.1rem",marginBottom:"0.75rem"}}>最近回执</h2>
|
||
{dash.recentReceipts.map(r => (
|
||
<div className="card" key={r.id}>
|
||
<div className="card-header">
|
||
<div className="card-title">{r.id}</div>
|
||
<span className={`badge ${r.result==="success"?"badge-success":"badge-warning"}`}>{r.result==="success"?"✅":"⚠️"}</span>
|
||
</div>
|
||
<div style={{fontSize:"0.85rem",color:"var(--t2)"}}>{r.operation} · {r.operator}</div>
|
||
<div style={{fontSize:"0.75rem",color:"var(--t2)",marginTop:"0.25rem"}}>{r.timestamp}</div>
|
||
</div>
|
||
))}
|
||
<button className="btn" onClick={() => onNavigate("receipt")} style={{marginTop:"0.5rem"}}>查看全部回执 →</button>
|
||
</div>;
|
||
}
|