chore: 提交所有工作进度 — SaaS 后端增强、Admin UI、桌面端集成

包含大量 SaaS 平台改进、Admin 管理后台更新、桌面端集成完善、
文档同步、测试文件重构等内容。为 QA 测试准备干净工作树。
This commit is contained in:
iven
2026-03-29 10:46:26 +08:00
parent 9a5fad2b59
commit 5fdf96c3f5
268 changed files with 22011 additions and 3886 deletions

View File

@@ -365,7 +365,7 @@ export function RightPanel() {
onClick={handleCancelEdit}
aria-label="Cancel edit"
>
Cancel
</Button>
<Button
variant="primary"
@@ -373,7 +373,7 @@ export function RightPanel() {
onClick={() => { handleSaveAgent().catch(silentErrorHandler('RightPanel')); }}
aria-label="Save edit"
>
Save
</Button>
</div>
) : (
@@ -383,7 +383,7 @@ export function RightPanel() {
onClick={handleStartEdit}
aria-label="Edit Agent"
>
Edit
</Button>
)
) : null}
@@ -395,20 +395,20 @@ export function RightPanel() {
transition={defaultTransition}
className="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-4 shadow-sm"
>
<div className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-3">About Me</div>
<div className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-3"></div>
{isEditingAgent && agentDraft ? (
<div className="space-y-2">
<AgentInput label="Name" value={agentDraft.name} onChange={(value) => setAgentDraft({ ...agentDraft, name: value })} />
<AgentInput label="Role" value={agentDraft.role} onChange={(value) => setAgentDraft({ ...agentDraft, role: value })} />
<AgentInput label="Nickname" value={agentDraft.nickname} onChange={(value) => setAgentDraft({ ...agentDraft, nickname: value })} />
<AgentInput label="Model" value={agentDraft.model} onChange={(value) => setAgentDraft({ ...agentDraft, model: value })} />
<AgentInput label="名称" value={agentDraft.name} onChange={(value) => setAgentDraft({ ...agentDraft, name: value })} />
<AgentInput label="角色" value={agentDraft.role} onChange={(value) => setAgentDraft({ ...agentDraft, role: value })} />
<AgentInput label="昵称" value={agentDraft.nickname} onChange={(value) => setAgentDraft({ ...agentDraft, nickname: value })} />
<AgentInput label="模型" value={agentDraft.model} onChange={(value) => setAgentDraft({ ...agentDraft, model: value })} />
</div>
) : (
<div className="space-y-3 text-sm">
<AgentRow label="Role" value={selectedClone?.role || '全能型 AI 助手'} />
<AgentRow label="Nickname" value={selectedClone?.nickname || '小龙'} />
<AgentRow label="Model" value={selectedClone?.model || currentModel} />
<AgentRow label="Emoji" value={selectedClone?.emoji || '🦞'} />
<AgentRow label="角色" value={selectedClone?.role || '全能型 AI 助手'} />
<AgentRow label="昵称" value={selectedClone?.nickname || '小龙'} />
<AgentRow label="模型" value={selectedClone?.model || currentModel} />
<AgentRow label="表情" value={selectedClone?.emoji || '🦞'} />
</div>
)}
</motion.div>
@@ -418,33 +418,33 @@ export function RightPanel() {
transition={defaultTransition}
className="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-4 shadow-sm"
>
<div className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-3">You in My Eyes</div>
<div className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-3"></div>
{isEditingAgent && agentDraft ? (
<div className="space-y-2">
<AgentInput label="Name" value={agentDraft.userName} onChange={(value) => setAgentDraft({ ...agentDraft, userName: value })} />
<AgentInput label="Role" value={agentDraft.userRole} onChange={(value) => setAgentDraft({ ...agentDraft, userRole: value })} />
<AgentInput label="Scenarios" value={agentDraft.scenarios} onChange={(value) => setAgentDraft({ ...agentDraft, scenarios: value })} placeholder="coding, research" />
<AgentInput label="Workspace" value={agentDraft.workspaceDir} onChange={(value) => setAgentDraft({ ...agentDraft, workspaceDir: value })} />
<AgentToggle label="File Restriction" checked={agentDraft.restrictFiles} onChange={(value) => setAgentDraft({ ...agentDraft, restrictFiles: value })} />
<AgentToggle label="Opt-in Program" checked={agentDraft.privacyOptIn} onChange={(value) => setAgentDraft({ ...agentDraft, privacyOptIn: value })} />
<AgentInput label="你的名称" value={agentDraft.userName} onChange={(value) => setAgentDraft({ ...agentDraft, userName: value })} />
<AgentInput label="你的角色" value={agentDraft.userRole} onChange={(value) => setAgentDraft({ ...agentDraft, userRole: value })} />
<AgentInput label="场景" value={agentDraft.scenarios} onChange={(value) => setAgentDraft({ ...agentDraft, scenarios: value })} placeholder="编程, 研究" />
<AgentInput label="工作区" value={agentDraft.workspaceDir} onChange={(value) => setAgentDraft({ ...agentDraft, workspaceDir: value })} />
<AgentToggle label="文件限制" checked={agentDraft.restrictFiles} onChange={(value) => setAgentDraft({ ...agentDraft, restrictFiles: value })} />
<AgentToggle label="隐私计划" checked={agentDraft.privacyOptIn} onChange={(value) => setAgentDraft({ ...agentDraft, privacyOptIn: value })} />
</div>
) : (
<div className="space-y-3 text-sm">
<AgentRow label="Name" value={userNameDisplay} />
<AgentRow label="Addressing" value={userAddressing} />
<AgentRow label="Timezone" value={localTimezone} />
<AgentRow label="你的名称" value={userNameDisplay} />
<AgentRow label="称呼方式" value={userAddressing} />
<AgentRow label="时区" value={localTimezone} />
<div className="flex gap-4">
<div className="w-16 text-gray-500 dark:text-gray-400">Focus</div>
<div className="w-16 text-gray-500 dark:text-gray-400"></div>
<div className="flex-1 flex flex-wrap gap-2">
{focusAreas.map((item) => (
<Badge key={item} variant="default">{item}</Badge>
))}
</div>
</div>
<AgentRow label="Workspace" value={selectedClone?.workspaceDir || workspaceInfo?.path || '~/.zclaw/zclaw-workspace'} />
<AgentRow label="Resolved" value={selectedClone?.workspaceResolvedPath || workspaceInfo?.resolvedPath || '-'} />
<AgentRow label="File Restriction" value={selectedClone?.restrictFiles ? 'Enabled' : 'Disabled'} />
<AgentRow label="Opt-in" value={selectedClone?.privacyOptIn ? 'Joined' : 'Not joined'} />
<AgentRow label="工作区" value={selectedClone?.workspaceDir || workspaceInfo?.path || '~/.zclaw/zclaw-workspace'} />
<AgentRow label="已解析" value={selectedClone?.workspaceResolvedPath || workspaceInfo?.resolvedPath || '-'} />
<AgentRow label="文件限制" value={selectedClone?.restrictFiles ? '已开启' : '已关闭'} />
<AgentRow label="隐私计划" value={selectedClone?.privacyOptIn ? '已加入' : '未加入'} />
</div>
)}
</motion.div>
@@ -455,9 +455,9 @@ export function RightPanel() {
className="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-4 shadow-sm"
>
<div className="flex items-center justify-between mb-3">
<div className="text-sm font-semibold text-gray-900 dark:text-gray-100">Bootstrap Files</div>
<div className="text-sm font-semibold text-gray-900 dark:text-gray-100"></div>
<Badge variant={selectedClone?.bootstrapReady ? 'success' : 'default'}>
{selectedClone?.bootstrapReady ? 'Generated' : 'Not generated'}
{selectedClone?.bootstrapReady ? '已生成' : '未生成'}
</Badge>
</div>
<div className="space-y-2 text-sm">
@@ -466,13 +466,13 @@ export function RightPanel() {
<div className="flex items-center justify-between gap-3">
<span className="font-medium text-gray-800 dark:text-gray-200">{file.name}</span>
<Badge variant={file.exists ? 'success' : 'error'}>
{file.exists ? 'Exists' : 'Missing'}
{file.exists ? '已存在' : '缺失'}
</Badge>
</div>
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400 break-all">{file.path}</div>
</div>
)) : (
<p className="text-sm text-gray-500 dark:text-gray-400">No bootstrap files generated for this Agent.</p>
<p className="text-sm text-gray-500 dark:text-gray-400"> Agent </p>
)}
</div>
</motion.div>
@@ -497,7 +497,7 @@ export function RightPanel() {
<WifiOff className="w-4 h-4 text-gray-500 dark:text-gray-400" />
)}
<Badge variant={connected ? 'success' : 'default'}>
Gateway {connected ? 'Connected' : connectionState === 'connecting' ? 'Connecting...' : connectionState === 'reconnecting' ? 'Reconnecting...' : 'Disconnected'}
Gateway {connected ? '已连接' : connectionState === 'connecting' ? '连接中...' : connectionState === 'reconnecting' ? '重连中...' : '未连接'}
</Badge>
</div>
{connected && (
@@ -506,8 +506,8 @@ export function RightPanel() {
size="sm"
onClick={() => { loadUsageStats(); loadPluginStatus(); loadClones(); }}
className="p-1 text-gray-500 hover:text-orange-500"
title="Refresh data"
aria-label="Refresh data"
title="刷新数据"
aria-label="刷新数据"
>
<RefreshCw className="w-3.5 h-3.5" />
</Button>
@@ -537,7 +537,7 @@ export function RightPanel() {
onClick={handleReconnect}
className="w-full"
>
Connect Gateway
Gateway
</Button>
</div>
)}