feat(hands): restructure Hands UI with Chinese localization
Major changes: - Add HandList.tsx component for left sidebar - Add HandTaskPanel.tsx for middle content area - Restructure Sidebar tabs: 分身/HANDS/Workflow - Remove Hands tab from RightPanel - Localize all UI text to Chinese - Archive legacy OpenClaw documentation - Add Hands integration lessons document - Update feature checklist with new components UI improvements: - Left sidebar now shows Hands list with status icons - Middle area shows selected Hand's tasks and results - Consistent styling with Tailwind CSS - Chinese status labels and buttons Documentation: - Create docs/archive/openclaw-legacy/ for old docs - Add docs/knowledge-base/hands-integration-lessons.md - Update docs/knowledge-base/feature-checklist.md - Update docs/knowledge-base/README.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,14 +20,14 @@ export function UsageStats() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="max-w-3xl">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h1 className="text-2xl font-bold text-gray-900">用量统计</h1>
|
||||
<button onClick={() => loadUsageStats()} className="text-sm text-gray-500 border border-gray-300 rounded-lg px-3 py-1.5 hover:bg-gray-50">
|
||||
<h1 className="text-xl font-bold text-gray-900">用量统计</h1>
|
||||
<button onClick={() => loadUsageStats()} className="text-xs text-gray-500 hover:text-gray-700 px-3 py-1.5 border border-gray-200 rounded-lg transition-colors">
|
||||
刷新
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500 mb-6">本设备所有已保存对话的 Token 用量汇总。</p>
|
||||
<div className="text-xs text-gray-500 mb-4">本设备所有已保存对话的 Token 用量汇总。</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 mb-8">
|
||||
<StatCard label="会话数" value={stats.totalSessions} />
|
||||
@@ -35,25 +35,29 @@ export function UsageStats() {
|
||||
<StatCard label="总 Token" value={formatTokens(stats.totalTokens)} />
|
||||
</div>
|
||||
|
||||
<h2 className="text-sm font-medium text-gray-700 mb-3">按模型</h2>
|
||||
<div className="bg-gray-50 rounded-xl p-5 space-y-4">
|
||||
<h2 className="text-sm font-semibold mb-4 text-gray-900">按模型</h2>
|
||||
<div className="bg-white rounded-xl border border-gray-200 divide-y divide-gray-100 shadow-sm">
|
||||
{models.length === 0 && (
|
||||
<p className="text-sm text-gray-400 text-center py-4">暂无数据</p>
|
||||
<div className="p-4 text-sm text-gray-400 text-center">暂无数据</div>
|
||||
)}
|
||||
{models.map(([model, data]) => {
|
||||
const total = data.inputTokens + data.outputTokens;
|
||||
const maxTokens = Math.max(...models.map(([, d]) => d.inputTokens + d.outputTokens), 1);
|
||||
const pct = (total / maxTokens) * 100;
|
||||
// Scale to 100% of the bar width based on max token usage across models for relative sizing.
|
||||
// Or we can just calculate input vs output within the model. Let's do input vs output within the total.
|
||||
const inputPct = (data.inputTokens / Math.max(total, 1)) * 100;
|
||||
const outputPct = (data.outputTokens / Math.max(total, 1)) * 100;
|
||||
|
||||
return (
|
||||
<div key={model}>
|
||||
<div className="flex justify-between items-center mb-1">
|
||||
<span className="text-sm font-medium text-gray-900">{model}</span>
|
||||
<div key={model} className="p-4">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="font-medium text-gray-900">{model}</span>
|
||||
<span className="text-xs text-gray-500">{data.messages} 条消息</span>
|
||||
</div>
|
||||
<div className="w-full bg-gray-200 rounded-full h-2 mb-1">
|
||||
<div className="bg-orange-500 h-2 rounded-full" style={{ width: `${pct}%` }} />
|
||||
<div className="h-2 bg-gray-100 rounded-full overflow-hidden mb-2 flex">
|
||||
<div className="bg-orange-500 h-full" style={{ width: `${inputPct}%` }} />
|
||||
<div className="bg-orange-200 h-full" style={{ width: `${outputPct}%` }} />
|
||||
</div>
|
||||
<div className="flex justify-between text-xs text-gray-400">
|
||||
<div className="flex justify-between text-xs text-gray-500">
|
||||
<span>输入: {formatTokens(data.inputTokens)}</span>
|
||||
<span>输出: {formatTokens(data.outputTokens)}</span>
|
||||
<span>总计: {formatTokens(total)}</span>
|
||||
@@ -68,9 +72,9 @@ export function UsageStats() {
|
||||
|
||||
function StatCard({ label, value }: { label: string; value: string | number }) {
|
||||
return (
|
||||
<div className="bg-gray-50 rounded-xl p-4 text-center">
|
||||
<div className="text-2xl font-bold text-gray-900">{value}</div>
|
||||
<div className="text-xs text-gray-500 mt-1">{label}</div>
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-5 shadow-sm">
|
||||
<div className="text-2xl font-bold mb-1 text-gray-900">{value}</div>
|
||||
<div className="text-xs text-gray-500">{label}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user