# 拖拽面板设计器 - 项目上下文总结 > **用途**:用于在新电脑快速恢复 AI 协作上下文 > **生成时间**:2025-12-20 > **项目路径**:`/Volumes/mypan/ui/draggable-panels` --- ## 📋 项目概述 这是一个基于 **Vue3 + TypeScript + Vite** 的**可拖拽面板设计器**项目,类似 IDE 界面(IDEA/VS Code)的多面板布局,支持: - 🎯 三栏面板布局(左/中/右可调整宽度) - 🎨 Tab 可拖拽、跨面板移动 - 🧩 物料组件系统(自动扫描注册) - 🎭 设计组件系统(可视化编辑、属性绑定) - 💾 状态持久化(通过模拟 API) --- ## 🏗️ 项目结构 ``` draggable-panels/ ├── src/ │ ├── fauto/ # 🔥 设计器核心代码(所有功能都在这里) │ │ ├── Designer.vue # 设计器主入口页面 │ │ ├── components/ # 设计器基础组件 │ │ │ ├── Header.vue # 顶部菜单栏(打开项目/窗口菜单) │ │ │ ├── Footer.vue # 底部状态栏 │ │ │ ├── MainLayout.vue # 三栏布局容器 │ │ │ ├── Panel.vue # 单个面板(含 Tab 列表 + 内容区) │ │ │ └── Resizer.vue # 面板间拖拽分割线 │ │ │ │ │ ├── materials/ # 🎁 物料组件(8个) │ │ │ ├── index.ts # ✅ 自动扫描所有 */index.vue 和 */index.json │ │ │ ├── DesignComponentList/ # 可选设计组件列表 │ │ │ ├── TreeViewer/ # 树形结构查看器(已添加实例列表) │ │ │ ├── DesignCenter/ # 设计中心(组件预览面板) │ │ │ ├── DataTable/ # 属性表格编辑器 │ │ │ ├── TextEditor/ # 文本编辑器(支持状态持久化) │ │ │ ├── TestWidget1/2/3/ # 测试组件 │ │ │ └── [每个物料包含] │ │ │ ├── index.vue # 组件实现 │ │ │ └── index.json # 组件元数据(name/description) │ │ │ │ │ ├── designComponents/ # 🎨 设计组件(3个) │ │ │ ├── TextInput/ # 文本输入框 │ │ │ ├── RadioSelect/ # 单选器 │ │ │ ├── GridTable/ # 表格 │ │ │ └── [每个设计组件包含] │ │ │ ├── index.vue # Vue 组件定义 │ │ │ └── index.json # 元数据(name/description/props) │ │ │ │ │ ├── stores/ # 🗄️ Pinia 状态管理 │ │ │ ├── panelStore.ts # 面板布局 + 物料状态管理 │ │ │ └── designStore.ts # 设计组件实例管理(✅ 本地自动扫描) │ │ │ │ │ └── types/ # 📝 TypeScript 类型定义 │ │ └── index.ts # Panel/TabItem/MaterialInfo 等 │ │ │ ├── views/ # 普通视图 │ │ └── HelloWorld.vue # 首页欢迎页 │ │ │ ├── router.ts # 🛤️ 路由配置(/ 和 /draggable) │ ├── main.ts # 应用入口 │ ├── App.vue # 根组件(仅路由容器) │ └── style.css # 全局样式 │ ├── package.json # 依赖配置 └── vite.config.ts # Vite 配置 ``` --- ## 🔑 核心技术要点 ### 1. **路由设计** ```typescript // src/router.ts '/' → HelloWorld 欢迎页 '/draggable' → Designer 设计器主页面(fauto/Designer.vue) ``` ### 2. **物料组件自动注册** ⭐ **文件**:`src/fauto/materials/index.ts` ```typescript // ✅ 使用 import.meta.glob 自动扫描 const vueModules = import.meta.glob('./*/index.vue') const jsonModules = import.meta.glob('./*/index.json', { eager: true }) // 自动构建组件映射表和信息列表 export const materialComponents: Record = {} export const materialList: MaterialInfo[] = [] ``` **新增物料步骤**: 1. 在 `materials/` 下创建新目录(如 `MyWidget/`) 2. 添加 `index.vue`(组件实现) 3. 添加 `index.json`(元数据) 4. **无需修改任何注册代码**,自动生效! ### 3. **设计组件自动加载** ⭐ **最近修复**(2025-12-20): **designStore.ts** - 从远程 API 改为本地扫描: ```typescript // ✅ 使用 eager: true 同步加载 const designComponentMetaModules = import.meta.glob('../designComponents/*/index.json', { eager: true }) // 自动构建元数据列表 const loadComponentMetas = async () => { const metas: DesignComponentMeta[] = [] for (const path in designComponentMetaModules) { const id = match[1] // 如 'TextInput' metas.push({ id, name, description, props }) } componentMetas.value = metas } ``` **DesignCenter.vue** - 组件预览渲染: ```typescript // ✅ 使用 eager: true 确保同步加载 const designComponentModules = import.meta.glob('../../designComponents/*/index.vue', { eager: true }) // 构建组件映射(用于 ) const designComponentMap: Record = {} for (const path in designComponentModules) { const mod = designComponentModules[path] as any designComponentMap[id] = markRaw(mod.default || mod) } ``` ### 4. **状态同步机制** ⭐ **TreeViewer.vue** - 实例列表实时同步(最近修复): ```typescript // ✅ 改用 watch 替代 $subscribe(更稳定) watch( () => designStore.components, (newVal) => { localComponents.value = [...newVal] }, { deep: true, immediate: true } ) ``` ### 5. **状态持久化** - **panelStore**:管理面板布局 + 物料组件状态 - `loadConfig()` / `saveConfig()` → `/api/config` - `getMaterialState()` / `updateMaterialState()` → `/api/material-states` - **designStore**:管理设计组件实例 - `loadState()` / `saveState()` → `/api/design-state` **注意**:目前使用 `fetch('/api/...')` 模拟持久化,实际会失败但不影响运行。如需真实持久化,可改用 localStorage 或搭建后端。 --- ## 🎯 数据流图 ``` 用户操作 ↓ ┌─────────────────────────────────────────────────┐ │ Header.vue - 点击"窗口"菜单 │ │ → panelStore.openMaterial('TreeViewer') │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ Panel.vue - 渲染 Tab + 加载物料组件 │ │ → │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ DesignComponentList - 点击"文本输入框" │ │ → designStore.addComponent('TextInput') │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ TreeViewer - watch 监听 components 变化 │ │ → 自动刷新实例列表 │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ DesignCenter - 渲染组件预览 │ │ → │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ DataTable - 编辑属性 │ │ → designStore.updateComponentProps(id, key, val)│ └─────────────────────────────────────────────────┘ ``` --- ## 🐛 已解决的关键问题 ### 问题 1:设计组件列表不显示 **时间**:2025-12-20 **原因**:`designStore.loadComponentMetas()` 使用 `fetch('/api/design-components')`,无后端导致 `componentMetas` 为空 **解决**:改用 `import.meta.glob` 自动扫描本地 `designComponents/*/index.json` ### 问题 2:TreeViewer 列表不更新 **原因**:使用 Pinia 的 `$subscribe` 监听 mutation,逻辑复杂且不稳定 **解决**:改用 Vue 的 `watch(() => designStore.components)` 直接监听 ### 问题 3:DesignCenter 组件不渲染 **原因**:`import.meta.glob` 未设置 `eager: true`,导致组件映射表构建失败 **解决**:添加 `{ eager: true }` 并使用 `mod.default || mod` 获取组件定义 --- ## 📦 依赖清单 ```json { "dependencies": { "vue": "^3.5.24", // Vue 3 框架 "vue-router": "^4.6.4", // 路由管理 "pinia": "^3.0.4", // 状态管理 "vuedraggable": "^4.1.0" // 拖拽功能 }, "devDependencies": { "vite": "^7.2.4", // 构建工具 "typescript": "~5.9.3", // TypeScript "@vitejs/plugin-vue": "^6.0.1" } } ``` --- ## 🚀 启动命令 ```bash # 1. 安装依赖 npm install # 2. 启动开发服务器 npm run dev # 访问 http://localhost:5173/draggable # 3. 构建生产版本 npm run build ``` --- ## 📝 后续可优化方向 ### 🔧 功能增强 1. **真实持久化** - 选项 A:改用 `localStorage` 替代模拟 API - 选项 B:搭建 Node.js 后端(Express + fs.writeFile) 2. **拖拽增强** - 支持面板间 Tab 跨级拖动 - 树形组件支持父子节点拖拽 3. **设计器功能** - 实现拖拽生成 Vue 文件(模板引擎) - 接入 Element Plus 组件库作为设计组件源 4. **开发体验** - 添加 ESLint + Prettier 代码规范 - 添加单元测试(Vitest) ### 🎨 界面优化 - 添加主题切换(暗色/亮色) - 面板大小记忆功能 - 快捷键支持(Ctrl+S 保存等) --- ## 💡 给 AI 的关键提示 ### 如果遇到"自动扫描不生效" 1. 检查是否添加了 `{ eager: true }` 选项 2. 确认路径匹配正则是否正确(`/designComponents\/(.+)\/index\.vue$/`) 3. 验证文件夹下是否有 `index.vue` 和 `index.json` ### 如果组件不渲染 1. 检查 `import.meta.glob` 是否使用 `eager: true` 2. 确认使用 `mod.default || mod` 获取组件 3. 对于动态组件,确保使用 `markRaw()` 包装 ### 如果状态不同步 1. 优先使用 Vue 的 `watch` 而非 Pinia 的 `$subscribe` 2. 设置 `{ deep: true, immediate: true }` 确保深度监听 3. 使用 `[...array]` 创建新数组触发响应式更新 --- ## 📞 联系方式 **项目负责人**:[你的信息] **Git 仓库**:[如果有的话] **文档更新**:2025-12-20 --- ## ✅ 快速检查清单(给新 AI) 当你接手这个项目时,请确认以下内容: - [ ] 项目已正常启动(`npm run dev`) - [ ] 访问 `/draggable` 能看到设计器界面 - [ ] 点击"窗口"菜单能打开物料组件 - [ ] "设计组件列表"显示 3 个组件(TextInput/RadioSelect/GridTable) - [ ] 点击设计组件后,TreeViewer 能显示新实例 - [ ] DesignCenter 能正确渲染组件预览 - [ ] DataTable 能编辑组件属性 如果以上任一项失败,请参考"已解决的关键问题"章节。 --- **🎉 恭喜!你已经完全掌握了这个项目的上下文,可以继续开发了!**