diff --git a/web/client/src/App.tsx b/web/client/src/App.tsx
new file mode 100644
index 0000000..09fba56
--- /dev/null
+++ b/web/client/src/App.tsx
@@ -0,0 +1,24 @@
+import { AppLayout } from '@/components/layout/AppLayout';
+import { ChatView } from '@/components/chat/ChatView';
+import { AccountList } from '@/components/accounts/AccountList';
+import { AssetGallery } from '@/components/assets/AssetGallery';
+import { ConfigForm } from '@/components/config/ConfigForm';
+import { useAppStore } from '@/store';
+
+function MainContent() {
+ const view = useAppStore((s) => s.activeView);
+ switch (view) {
+ case 'chat': return ;
+ case 'accounts': return ;
+ case 'assets': return ;
+ case 'config': return ;
+ }
+}
+
+export default function App() {
+ return (
+
+
+
+ );
+}
diff --git a/web/client/src/components/accounts/AccountList.tsx b/web/client/src/components/accounts/AccountList.tsx
new file mode 100644
index 0000000..3ad32ea
--- /dev/null
+++ b/web/client/src/components/accounts/AccountList.tsx
@@ -0,0 +1,3 @@
+export function AccountList() {
+ return
账户管理
;
+}
diff --git a/web/client/src/components/assets/AssetGallery.tsx b/web/client/src/components/assets/AssetGallery.tsx
new file mode 100644
index 0000000..fb0dee6
--- /dev/null
+++ b/web/client/src/components/assets/AssetGallery.tsx
@@ -0,0 +1,3 @@
+export function AssetGallery() {
+ return 资产画廊
;
+}
diff --git a/web/client/src/components/chat/ChatView.tsx b/web/client/src/components/chat/ChatView.tsx
new file mode 100644
index 0000000..9672061
--- /dev/null
+++ b/web/client/src/components/chat/ChatView.tsx
@@ -0,0 +1,3 @@
+export function ChatView() {
+ return 选择或开始新对话
;
+}
diff --git a/web/client/src/components/config/ConfigForm.tsx b/web/client/src/components/config/ConfigForm.tsx
new file mode 100644
index 0000000..57b39cb
--- /dev/null
+++ b/web/client/src/components/config/ConfigForm.tsx
@@ -0,0 +1,3 @@
+export function ConfigForm() {
+ return 设置
;
+}
diff --git a/web/client/src/components/layout/AppLayout.tsx b/web/client/src/components/layout/AppLayout.tsx
new file mode 100644
index 0000000..c0bc784
--- /dev/null
+++ b/web/client/src/components/layout/AppLayout.tsx
@@ -0,0 +1,17 @@
+import { Sidebar } from './Sidebar';
+import { MiddlePanel } from './MiddlePanel';
+import { useAppStore } from '@/store';
+
+export function AppLayout({ children }: { children: React.ReactNode }) {
+ const activeView = useAppStore((s) => s.activeView);
+
+ return (
+
+
+ {activeView === 'chat' && }
+
+ {children}
+
+
+ );
+}
diff --git a/web/client/src/components/layout/MiddlePanel.tsx b/web/client/src/components/layout/MiddlePanel.tsx
new file mode 100644
index 0000000..7c3ea97
--- /dev/null
+++ b/web/client/src/components/layout/MiddlePanel.tsx
@@ -0,0 +1,38 @@
+import { Plus } from 'lucide-react';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { ScrollArea } from '@/components/ui/scroll-area';
+import { useAppStore } from '@/store';
+
+export function MiddlePanel() {
+ const { conversations, activeConversationId, setActiveConversationId } = useAppStore();
+
+ return (
+
+ );
+}
diff --git a/web/client/src/components/layout/Sidebar.tsx b/web/client/src/components/layout/Sidebar.tsx
new file mode 100644
index 0000000..88c2bf9
--- /dev/null
+++ b/web/client/src/components/layout/Sidebar.tsx
@@ -0,0 +1,35 @@
+import { MessageCircle, FolderOpen, Image, Settings } from 'lucide-react';
+import { useAppStore } from '@/store';
+import type { NavView } from '@/types';
+import { cn } from '@/lib/utils';
+
+const navItems: { id: NavView; icon: typeof MessageCircle; label: string }[] = [
+ { id: 'chat', icon: MessageCircle, label: '对话' },
+ { id: 'accounts', icon: FolderOpen, label: '账户' },
+ { id: 'assets', icon: Image, label: '资产' },
+ { id: 'config', icon: Settings, label: '设置' },
+];
+
+export function Sidebar() {
+ const { activeView, setActiveView } = useAppStore();
+
+ return (
+
+ );
+}
diff --git a/web/client/src/store/index.ts b/web/client/src/store/index.ts
new file mode 100644
index 0000000..1a77c11
--- /dev/null
+++ b/web/client/src/store/index.ts
@@ -0,0 +1,24 @@
+import { create } from 'zustand';
+import type { NavView, Conversation } from '@/types';
+
+interface AppState {
+ activeView: NavView;
+ setActiveView: (view: NavView) => void;
+ selectedAccountId: string | null;
+ setSelectedAccountId: (id: string | null) => void;
+ activeConversationId: string | null;
+ setActiveConversationId: (id: string | null) => void;
+ conversations: Conversation[];
+ setConversations: (list: Conversation[]) => void;
+}
+
+export const useAppStore = create((set) => ({
+ activeView: 'chat',
+ setActiveView: (view) => set({ activeView: view }),
+ selectedAccountId: null,
+ setSelectedAccountId: (id) => set({ selectedAccountId: id }),
+ activeConversationId: null,
+ setActiveConversationId: (id) => set({ activeConversationId: id }),
+ conversations: [],
+ setConversations: (list) => set({ conversations: list }),
+}));
diff --git a/web/client/src/types/index.ts b/web/client/src/types/index.ts
new file mode 100644
index 0000000..73efb68
--- /dev/null
+++ b/web/client/src/types/index.ts
@@ -0,0 +1,53 @@
+export type NavView = 'chat' | 'accounts' | 'assets' | 'config';
+
+export interface Account {
+ id: string;
+ name: string;
+ description: string;
+ defaultFormat: string;
+ imageModel: string;
+ videoModel: string;
+ batchSize: number;
+ ttsVoice: string;
+ ttsInstruction: string;
+ storyboardPrompt: string;
+ imageStylePrompt: string;
+ videoStylePrompt: string;
+ references: { file: string; url?: string }[];
+ capcut: Record;
+}
+
+export interface Conversation {
+ id: string;
+ title: string;
+ account_id: string | null;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface Message {
+ id: string;
+ conversation_id: string;
+ role: 'user' | 'assistant' | 'system' | 'tool';
+ content: string;
+ tool_calls?: unknown;
+ created_at: string;
+}
+
+export interface Asset {
+ id: string;
+ account_id: string | null;
+ manifest_path: string | null;
+ type: 'image' | 'video';
+ file_path: string;
+ url: string | null;
+ shot_index: number | null;
+ created_at: string;
+}
+
+export interface ConfigItem {
+ id: string;
+ key: string;
+ value: Record;
+ updated_at: string;
+}