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

@@ -12,6 +12,7 @@ import { HandApprovalModal } from './components/HandApprovalModal';
import { TopBar } from './components/TopBar';
import { DetailDrawer } from './components/DetailDrawer';
import { useConnectionStore } from './store/connectionStore';
import { useSaaSStore } from './store/saasStore';
import { useHandStore, type HandRun } from './store/handStore';
import { useChatStore } from './store/chatStore';
import { initializeStores } from './store';
@@ -19,9 +20,10 @@ import { getStoredGatewayToken } from './lib/gateway-client';
import { pageVariants, defaultTransition, fadeInVariants } from './lib/animations';
import { Loader2 } from 'lucide-react';
import { isTauriRuntime, getLocalGatewayStatus, startLocalGateway } from './lib/tauri-gateway';
import { LoginPage } from './components/LoginPage';
import { useOnboarding } from './lib/use-onboarding';
import { intelligenceClient } from './lib/intelligence-client';
import { loadEmbeddingConfig } from './lib/embedding-client';
import { loadEmbeddingConfig, loadEmbeddingApiKey } from './lib/embedding-client';
import { invoke } from '@tauri-apps/api/core';
import { useProposalNotifications, ProposalNotificationHandler } from './lib/useProposalNotifications';
import { useToast } from './components/ui/Toast';
@@ -54,10 +56,11 @@ function App() {
const [showApprovalModal, setShowApprovalModal] = useState(false);
const connect = useConnectionStore((s) => s.connect);
const isLoggedIn = useSaaSStore((s) => s.isLoggedIn);
const hands = useHandStore((s) => s.hands);
const approveHand = useHandStore((s) => s.approveHand);
const loadHands = useHandStore((s) => s.loadHands);
const { setCurrentAgent, newConversation } = useChatStore();
const { setCurrentAgent } = useChatStore();
const { isNeeded: onboardingNeeded, isLoading: onboardingLoading, markCompleted } = useOnboarding();
// Proposal notifications
@@ -132,6 +135,9 @@ function App() {
let mounted = true;
const bootstrap = async () => {
// 未登录时不启动 bootstrap
if (!useSaaSStore.getState().isLoggedIn) return;
try {
// Step 1: Check and start local gateway in Tauri environment
if (isTauriRuntime()) {
@@ -234,12 +240,33 @@ function App() {
// Step 5: Restore embedding config to Rust backend
try {
// Migrate plaintext embedding apiKey to secure storage if present
try {
const embStored = localStorage.getItem('zclaw-embedding-config');
if (embStored) {
const embParsed = JSON.parse(embStored);
if (embParsed.apiKey && embParsed.apiKey.trim()) {
const { saveEmbeddingApiKey } = await import('./lib/embedding-client');
const { secureStorage } = await import('./lib/secure-storage');
// Only migrate if not already in secure storage
const existing = await secureStorage.get('zclaw-secure-embedding-apikey');
if (!existing) {
await saveEmbeddingApiKey(embParsed.apiKey);
}
// Strip apiKey from localStorage
const { apiKey: _, ...stripped } = embParsed;
localStorage.setItem('zclaw-embedding-config', JSON.stringify(stripped));
}
}
} catch { /* migration failure is non-critical */ }
const embConfig = loadEmbeddingConfig();
if (embConfig.enabled && embConfig.provider !== 'local' && embConfig.apiKey) {
const embApiKey = await loadEmbeddingApiKey();
if (embConfig.enabled && embConfig.provider !== 'local' && embApiKey) {
setBootstrapStatus('Restoring embedding configuration...');
await invoke('viking_configure_embedding', {
provider: embConfig.provider,
apiKey: embConfig.apiKey,
apiKey: embApiKey,
model: embConfig.model || undefined,
endpoint: embConfig.endpoint || undefined,
});
@@ -252,8 +279,10 @@ function App() {
// Step 5b: Configure summary driver using active LLM (for L0/L1 generation)
try {
const { getDefaultModelConfig } = await import('./store/connectionStore');
const modelConfig = getDefaultModelConfig();
const { getDefaultModelConfigAsync, migrateModelApiKeysToSecureStorage } = await import('./store/connectionStore');
// Migrate any plaintext API keys to secure storage (idempotent)
await migrateModelApiKeysToSecureStorage();
const modelConfig = await getDefaultModelConfigAsync();
if (modelConfig && modelConfig.apiKey && modelConfig.baseUrl) {
setBootstrapStatus('Configuring summary driver...');
await invoke('viking_configure_summary_driver', {
@@ -288,7 +317,7 @@ function App() {
clearInterval(window.__ZCLAW_STATS_SYNC_INTERVAL__);
}
};
}, [connect, onboardingNeeded, onboardingLoading]);
}, [connect, onboardingNeeded, onboardingLoading, isLoggedIn]);
// Handle onboarding completion
const handleOnboardingSuccess = (clone: Clone) => {
@@ -312,11 +341,10 @@ function App() {
setMainContentView(view);
};
// 处理新对话
const handleNewChat = () => {
newConversation();
setMainContentView('chat');
};
// 登录门禁 — 必须登录才能使用
if (!isLoggedIn) {
return <LoginPage />;
}
if (view === 'settings') {
return <SettingsLayout onBack={() => setView('main')} />;
@@ -384,7 +412,6 @@ function App() {
<Sidebar
onOpenSettings={() => setView('settings')}
onMainViewChange={handleMainViewChange}
onNewChat={handleNewChat}
/>
{/* 主内容区 */}