feat(frontend): 添加 Zustand store 架构

- 创建 5 个领域 store:runtimeStore, marketStore, portfolioStore, agentStore, uiStore
- 更新 CLAUDE.md 记录架构改进
- Zustand 已安装但 stores 尚未在 App.jsx 中使用(渐进迁移)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-23 17:44:17 +08:00
parent 06a23c32a4
commit 0f1bc2bb39
7 changed files with 520 additions and 113 deletions

View File

@@ -0,0 +1,58 @@
import { create } from 'zustand';
/**
* Agent Store - Agent skills, profiles, workspaces
*/
export const useAgentStore = create((set) => ({
// Selected agent for skill/workspace editing
selectedSkillAgentId: null,
setSelectedSkillAgentId: (selectedSkillAgentId) => set({ selectedSkillAgentId }),
// Agent profiles
agentProfilesByAgent: {},
setAgentProfilesByAgent: (agentProfilesByAgent) => set({ agentProfilesByAgent }),
// Agent skills
agentSkillsByAgent: {},
setAgentSkillsByAgent: (agentSkillsByAgent) => set({ agentSkillsByAgent }),
// Skill details
skillDetailsByName: {},
setSkillDetailsByName: (skillDetailsByName) => set({ skillDetailsByName }),
// Local skill drafts
localSkillDraftsByKey: {},
setLocalSkillDraftsByKey: (localSkillDraftsByKey) => set({ localSkillDraftsByKey }),
// Loading states
isAgentSkillsLoading: false,
setIsAgentSkillsLoading: (isAgentSkillsLoading) => set({ isAgentSkillsLoading }),
skillDetailLoadingKey: null,
setSkillDetailLoadingKey: (skillDetailLoadingKey) => set({ skillDetailLoadingKey }),
agentSkillsSavingKey: null,
setAgentSkillsSavingKey: (agentSkillsSavingKey) => set({ agentSkillsSavingKey }),
agentSkillsFeedback: null,
setAgentSkillsFeedback: (agentSkillsFeedback) => set({ agentSkillsFeedback }),
// Workspace files
selectedWorkspaceFile: null,
setSelectedWorkspaceFile: (selectedWorkspaceFile) => set({ selectedWorkspaceFile }),
workspaceFilesByAgent: {},
setWorkspaceFilesByAgent: (workspaceFilesByAgent) => set({ workspaceFilesByAgent }),
workspaceDraftContent: '',
setWorkspaceDraftContent: (workspaceDraftContent) => set({ workspaceDraftContent }),
isWorkspaceFileLoading: false,
setIsWorkspaceFileLoading: (isWorkspaceFileLoading) => set({ isWorkspaceFileLoading }),
workspaceFileSavingKey: null,
setWorkspaceFileSavingKey: (workspaceFileSavingKey) => set({ workspaceFileSavingKey }),
workspaceFileFeedback: null,
setWorkspaceFileFeedback: (workspaceFileFeedback) => set({ workspaceFileFeedback }),
}));

View File

@@ -0,0 +1,5 @@
export { useRuntimeStore } from './runtimeStore';
export { useMarketStore } from './marketStore';
export { usePortfolioStore } from './portfolioStore';
export { useAgentStore } from './agentStore';
export { useUIStore } from './uiStore';

View File

@@ -0,0 +1,44 @@
import { create } from 'zustand';
/**
* Market Store - Market data, stock prices, news
*/
export const useMarketStore = create((set) => ({
// Ticker prices
tickers: [],
setTickers: (tickers) => set({ tickers }),
rollingTickers: {},
setRollingTickers: (rollingTickers) => set({ rollingTickers }),
// Price history
priceHistoryByTicker: {},
setPriceHistoryByTicker: (priceHistoryByTicker) => set({ priceHistoryByTicker }),
// OHLC history
ohlcHistoryByTicker: {},
setOhlcHistoryByTicker: (ohlcHistoryByTicker) => set({ ohlcHistoryByTicker }),
// History source tracking
historySourceByTicker: {},
setHistorySourceByTicker: (historySourceByTicker) => set({ historySourceByTicker }),
// Explain events
explainEventsByTicker: {},
setExplainEventsByTicker: (explainEventsByTicker) => set({ explainEventsByTicker }),
// Selected explain symbol
selectedExplainSymbol: '',
setSelectedExplainSymbol: (selectedExplainSymbol) => set({ selectedExplainSymbol }),
// News by ticker
newsByTicker: {},
setNewsByTicker: (newsByTicker) => set({ newsByTicker }),
// Insider trades
insiderTradesByTicker: {},
setInsiderTradesByTicker: (insiderTradesByTicker) => set({ insiderTradesByTicker }),
// Technical indicators
technicalIndicatorsByTicker: {},
setTechnicalIndicatorsByTicker: (technicalIndicatorsByTicker) => set({ technicalIndicatorsByTicker }),
}));

View File

@@ -0,0 +1,38 @@
import { create } from 'zustand';
/**
* Portfolio Store - Portfolio data, holdings, trades, statistics
*/
export const usePortfolioStore = create((set) => ({
// Portfolio data
portfolioData: {
netValue: 10000,
pnl: 0,
equity: [],
baseline: [],
baseline_vw: [],
momentum: [],
strategies: [],
equity_return: 0,
baseline_return: 0,
baseline_vw_return: 0,
momentum_return: 0,
},
setPortfolioData: (portfolioData) => set({ portfolioData }),
// Holdings
holdings: [],
setHoldings: (holdings) => set({ holdings }),
// Trades
trades: [],
setTrades: (trades) => set({ trades }),
// Statistics
stats: null,
setStats: (stats) => set({ stats }),
// Leaderboard
leaderboard: [],
setLeaderboard: (leaderboard) => set({ leaderboard }),
}));

View File

@@ -0,0 +1,90 @@
import { create } from 'zustand';
/**
* Runtime Store - Connection state and runtime configuration
*/
export const useRuntimeStore = create((set) => ({
// Connection state
isConnected: false,
connectionStatus: 'connecting', // 'connecting' | 'connected' | 'disconnected'
setIsConnected: (isConnected) => set({ isConnected }),
setConnectionStatus: (connectionStatus) => set({ connectionStatus }),
// System state
systemStatus: 'initializing', // 'initializing' | 'running' | 'completed'
currentDate: null,
setSystemStatus: (systemStatus) => set({ systemStatus }),
setCurrentDate: (currentDate) => set({ currentDate }),
// Progress
progress: { current: 0, total: 0 },
setProgress: (progress) => set({ progress }),
// Server mode
serverMode: null, // 'live' | 'backtest' | null
setServerMode: (serverMode) => set({ serverMode }),
// Market status
marketStatus: null,
virtualTime: null,
setMarketStatus: (marketStatus) => set({ marketStatus }),
setVirtualTime: (virtualTime) => set({ virtualTime }),
// Data sources
dataSources: null,
setDataSources: (dataSources) => set({ dataSources }),
// Runtime config
runtimeConfig: null,
setRuntimeConfig: (runtimeConfig) => set({ runtimeConfig }),
// Watchlist panel
isWatchlistPanelOpen: false,
setIsWatchlistPanelOpen: (isWatchlistPanelOpen) => set({ isWatchlistPanelOpen }),
// Watchlist draft
watchlistDraftSymbols: [],
watchlistInputValue: '',
watchlistFeedback: null,
isWatchlistSaving: false,
setWatchlistDraftSymbols: (watchlistDraftSymbols) => set({ watchlistDraftSymbols }),
setWatchlistInputValue: (watchlistInputValue) => set({ watchlistInputValue }),
setWatchlistFeedback: (watchlistFeedback) => set({ watchlistFeedback }),
setIsWatchlistSaving: (isWatchlistSaving) => set({ isWatchlistSaving }),
// Runtime settings panel
isRuntimeSettingsOpen: false,
setIsRuntimeSettingsOpen: (isRuntimeSettingsOpen) => set({ isRuntimeSettingsOpen }),
// Runtime config drafts
scheduleModeDraft: 'daily',
intervalMinutesDraft: '60',
triggerTimeDraft: '09:30',
maxCommCyclesDraft: '2',
initialCashDraft: '100000',
marginRequirementDraft: '0',
enableMemoryDraft: false,
modeDraft: 'live',
pollIntervalDraft: '10',
startDateDraft: '',
endDateDraft: '',
enableMockDraft: false,
setScheduleModeDraft: (scheduleModeDraft) => set({ scheduleModeDraft }),
setIntervalMinutesDraft: (intervalMinutesDraft) => set({ intervalMinutesDraft }),
setTriggerTimeDraft: (triggerTimeDraft) => set({ triggerTimeDraft }),
setMaxCommCyclesDraft: (maxCommCyclesDraft) => set({ maxCommCyclesDraft }),
setInitialCashDraft: (initialCashDraft) => set({ initialCashDraft }),
setMarginRequirementDraft: (marginRequirementDraft) => set({ marginRequirementDraft }),
setEnableMemoryDraft: (enableMemoryDraft) => set({ enableMemoryDraft }),
setModeDraft: (modeDraft) => set({ modeDraft }),
setPollIntervalDraft: (pollIntervalDraft) => set({ pollIntervalDraft }),
setStartDateDraft: (startDateDraft) => set({ startDateDraft }),
setEndDateDraft: (endDateDraft) => set({ endDateDraft }),
setEnableMockDraft: (enableMockDraft) => set({ enableMockDraft }),
// Runtime config feedback
runtimeConfigFeedback: null,
isRuntimeConfigSaving: false,
setRuntimeConfigFeedback: (runtimeConfigFeedback) => set({ runtimeConfigFeedback }),
setIsRuntimeConfigSaving: (isRuntimeConfigSaving) => set({ isRuntimeConfigSaving }),
}));

View File

@@ -0,0 +1,40 @@
import { create } from 'zustand';
/**
* UI Store - UI state, view management, layout
*/
export const useUIStore = create((set) => ({
// Current view
currentView: 'traders', // 'traders' | 'room' | 'explain' | 'chart' | 'statistics' | 'runtime'
setCurrentView: (currentView) => set({ currentView }),
// Chart tab
chartTab: 'all',
setChartTab: (chartTab) => set({ chartTab }),
// Initial animation
isInitialAnimating: true,
setIsInitialAnimating: (isInitialAnimating) => set({ isInitialAnimating }),
// Last update timestamp
lastUpdate: new Date(),
setLastUpdate: (lastUpdate) => set({ lastUpdate }),
// Is updating
isUpdating: false,
setIsUpdating: (isUpdating) => set({ isUpdating }),
// Room bubbles
bubbles: {},
setBubbles: (bubbles) => set({ bubbles }),
// Resizable panels
leftWidth: 70,
setLeftWidth: (leftWidth) => set({ leftWidth }),
isResizing: false,
setIsResizing: (isResizing) => set({ isResizing }),
// Now timestamp (for current time display)
now: new Date(),
setNow: (now) => set({ now }),
}));