diff --git a/copy-of-inkflow-script-ai/App.tsx b/copy-of-inkflow-script-ai/App.tsx index b73c1e1..148c872 100644 --- a/copy-of-inkflow-script-ai/App.tsx +++ b/copy-of-inkflow-script-ai/App.tsx @@ -1,263 +1,437 @@ +import React, { useMemo, useState } from 'react'; +import { + BadgeCheck, + Crown, + MessageCircle, + Pin, + Search, + Send, + ShieldCheck, + Star, + UserRound, + Users, + Wallet, + X, +} from 'lucide-react'; -import React, { useState } from 'react'; -import { Navigation } from './components/Navigation'; -import { AICopilot } from './components/AICopilot'; -import { CharactersModule } from './components/modules/Characters'; -import { NovelAdaptationModule } from './components/modules/NovelAdaptation'; -import { OutlineModule } from './components/modules/Outline'; -import { PlotModule } from './components/modules/Plot'; -import { ScriptEditor } from './components/modules/ScriptEditor'; -import { StoryboardModule } from './components/modules/Storyboard'; -import { ModuleType, ProjectData, ScriptBlockType, AppLanguage, ScriptFormat } from './types'; -import { TrendingUp, Users, Target, BarChart3, BookText } from 'lucide-react'; -import { getTranslation } from './utils/translations'; - -const INITIAL_DATA: ProjectData = { - title: '无标题作品', - logline: '', - genre: '剧情', - scriptFormat: ScriptFormat.MOVIE, // Explicitly initialize script format - marketAnalysis: { - targetAudience: '', - marketPositioning: '', - commercialsellingPoints: '' - }, - novelChapters: [], - characters: [], - relationships: [], - totalOutline: '', // Initial empty total outline - outline: [ - { - id: '1', - title: '第一幕:铺垫', - content: '', - tips: '介绍主角及其所处的世界,引发激励事件。 (0-30min)', - scenes: [] - }, - { - id: '2', - title: '第二幕:对抗', - content: '', - tips: '主角追求目标过程中冲突升级,遭遇重重阻碍。 (30-90min)', - scenes: [] - }, - { - id: '3', - title: '第三幕:结局', - content: '', - tips: '冲突解决后的余波,展现新的常态。 (90min+)', - scenes: [] - }, - ], - plotEvents: [], - script: [ - { id: '0', type: ScriptBlockType.SCENE_HEADING, content: '内景. 地点 - 日' }, - { id: '1', type: ScriptBlockType.ACTION, content: '动作描述...' }, - ] +type MembershipLevel = '普通会员' | '黄金会员' | '钻石会员'; +type TabKey = 'projects' | 'users'; +type ProjectCategory = '全部' | '本地生活' | '私域增长' | '跨境电商' | '品牌投放'; +type ProjectStage = '待沟通' | '跟进中' | '已签约'; + +type ContactCard = { + id: string; + name: string; + role: string; + company: string; + city: string; + phone: string; + wechat: string; + level: MembershipLevel; + exchanged?: boolean; +}; + +type ProjectMatch = { + id: string; + projectName: string; + category: Exclude; + demand: string; + supplier: string; + score: number; + stage: ProjectStage; +}; + +type UserItem = { + id: string; + name: string; + role: '甲方' | '服务商' | '渠道'; + status: '正常' | '待审核' | '冻结'; + level: MembershipLevel; +}; + +type TopCard = { + id: string; + title: string; + city: string; + budget: string; + daysLeft: number; }; +const PROJECT_CATEGORIES: ProjectCategory[] = ['全部', '本地生活', '私域增长', '跨境电商', '品牌投放']; + +const INITIAL_PROJECTS: ProjectMatch[] = [ + { id: 'p1', projectName: '华南门店私域升级', category: '私域增长', demand: '私域系统搭建', supplier: '增长工场', score: 92, stage: '跟进中' }, + { id: 'p2', projectName: '连锁美业达人投放', category: '品牌投放', demand: '抖音达人投放', supplier: '星河传媒', score: 88, stage: '待沟通' }, + { id: 'p3', projectName: '跨境平台招商拓展', category: '跨境电商', demand: '区域BD招商', supplier: '海豚渠道', score: 95, stage: '已签约' }, + { id: 'p4', projectName: '商超到店流量提升', category: '本地生活', demand: '团购运营+直播', supplier: '聚客网络', score: 86, stage: '待沟通' }, +]; + +const INITIAL_CONTACTS: ContactCard[] = [ + { id: 'c1', name: '王明', role: '商务总监', company: '云火增长', city: '杭州', phone: '138****1098', wechat: 'wm-growth', level: '黄金会员' }, + { id: 'c2', name: '陈琪', role: '渠道合伙人', company: '启航电商', city: '广州', phone: '139****7850', wechat: 'chenq-bd', level: '钻石会员' }, +]; + +const INITIAL_TOP_CARDS: TopCard[] = [ + { id: 't1', title: '连锁餐饮品牌短视频代运营需求', city: '上海', budget: '8万-15万/月', daysLeft: 6 }, + { id: 't2', title: '母婴私域SCRM实施项目', city: '广州', budget: '20万+', daysLeft: 2 }, +]; + +const INITIAL_USERS: UserItem[] = [ + { id: 'u1', name: '李总', role: '甲方', status: '正常', level: '钻石会员' }, + { id: 'u2', name: '陈经理', role: '服务商', status: '待审核', level: '普通会员' }, + { id: 'u3', name: '赵女士', role: '渠道', status: '正常', level: '黄金会员' }, +]; + +const TABS: Array<{ key: TabKey; label: string; icon: React.ReactNode }> = [ + { key: 'projects', label: '项目', icon: }, + { key: 'users', label: '用户管理', icon: }, +]; + export default function App() { - const [currentModule, setCurrentModule] = useState(ModuleType.DASHBOARD); - const [projectData, setProjectData] = useState(INITIAL_DATA); - const [isAiOpen, setIsAiOpen] = useState(true); - const [language, setLanguage] = useState('zh-CN'); - - const t = getTranslation(language); - - const [history, setHistory] = useState([]); - const [future, setFuture] = useState([]); - - const undo = () => { - if (history.length === 0) return; - const previous = history[history.length - 1]; - const newHistory = history.slice(0, -1); - - setFuture(prev => [projectData, ...prev]); - setProjectData(previous); - setHistory(newHistory); + const [tab, setTab] = useState('projects'); + const [category, setCategory] = useState('全部'); + const [keyword, setKeyword] = useState(''); + const [projects, setProjects] = useState(INITIAL_PROJECTS); + const [contacts, setContacts] = useState(INITIAL_CONTACTS); + const [topCards, setTopCards] = useState(INITIAL_TOP_CARDS); + const [users, setUsers] = useState(INITIAL_USERS); + const [memberLevel, setMemberLevel] = useState('黄金会员'); + const [memberDays, setMemberDays] = useState(126); + const [messages, setMessages] = useState(['您好,我们可以承接本地生活项目,方便聊下需求吗?']); + const [draft, setDraft] = useState(''); + const [notice, setNotice] = useState(''); + const [showCreate, setShowCreate] = useState(false); + + const [newProject, setNewProject] = useState({ + name: '', + category: '本地生活' as Exclude, + demand: '', + supplier: '', + }); + + const filteredProjects = useMemo(() => { + return projects.filter((item) => { + const matchCategory = category === '全部' || item.category === category; + const matchKeyword = + !keyword.trim() || + item.projectName.includes(keyword) || + item.demand.includes(keyword) || + item.supplier.includes(keyword); + return matchCategory && matchKeyword; + }); + }, [category, keyword, projects]); + + const publishNotice = (text: string) => { + setNotice(text); + window.setTimeout(() => setNotice(''), 1600); + }; + + const sendMessage = () => { + const value = draft.trim(); + if (!value) return; + setMessages((prev) => [...prev, value]); + setDraft(''); }; - const redo = () => { - if (future.length === 0) return; - const next = future[0]; - const newFuture = future.slice(1); - - setHistory(prev => [...prev, projectData]); - setProjectData(next); - setFuture(newFuture); + const advanceProjectStage = (id: string) => { + const order: ProjectStage[] = ['待沟通', '跟进中', '已签约']; + setProjects((prev) => + prev.map((project) => { + if (project.id !== id) return project; + const next = order[Math.min(order.indexOf(project.stage) + 1, 2)]; + return { ...project, stage: next }; + }), + ); + publishNotice('项目状态已推进'); }; - const updateProject = (newData: Partial, saveHistory: boolean = false) => { - if (saveHistory) { - setHistory(prev => [...prev, projectData]); - setFuture([]); + const createProject = () => { + if (!newProject.name.trim() || !newProject.demand.trim() || !newProject.supplier.trim()) { + publishNotice('请先填写完整项目信息'); + return; } - setProjectData(prev => ({ ...prev, ...newData })); + setProjects((prev) => [ + { + id: `p${Date.now()}`, + projectName: newProject.name.trim(), + category: newProject.category, + demand: newProject.demand.trim(), + supplier: newProject.supplier.trim(), + score: 80, + stage: '待沟通', + }, + ...prev, + ]); + setNewProject({ name: '', category: '本地生活', demand: '', supplier: '' }); + setShowCreate(false); + publishNotice('项目已创建'); }; - const updateMarketAnalysis = (field: keyof typeof projectData.marketAnalysis, value: string) => { - updateProject({ - marketAnalysis: { - ...projectData.marketAnalysis, - [field]: value - } - }); + const toggleExchange = (id: string) => { + setContacts((prev) => prev.map((contact) => (contact.id === id ? { ...contact, exchanged: !contact.exchanged } : contact))); }; - const renderModule = () => { - switch (currentModule) { - case ModuleType.DASHBOARD: - return ( -
-
- updateProject({ title: e.target.value })} - className="text-4xl font-serif font-bold text-ink-900 mb-4 text-center bg-transparent border-b-2 border-transparent hover:border-ink-200 focus:border-accent-500 focus:outline-none w-full transition-colors placeholder-ink-300" - placeholder={t.dashboard.titlePlaceholder} - /> - -
- {t.dashboard.genre} - updateProject({ genre: e.target.value })} - className="text-sm font-medium text-accent-600 bg-accent-50 px-3 py-1 rounded-full text-center w-32 focus:outline-none focus:ring-1 focus:ring-accent-500" - placeholder="..." - /> -
- -
-