# Fauto Design - 开发指南 本文档为开发者提供项目的开发规范、扩展指南和最佳实践。 --- ## 目录 1. [开发环境配置](#1-开发环境配置) 2. [代码规范](#2-代码规范) 3. [Vue页面规范](#3-vue页面规范) 4. [设计组件开发](#4-设计组件开发) 5. [物料组件开发](#5-物料组件开发) 6. [插件开发](#6-插件开发) 7. [后端服务扩展](#7-后端服务扩展) 8. [常见问题与经验](#8-常见问题与经验) --- ## 1. 开发环境配置 ### 1.1 前端环境 ```bash cd draggable-panels npm install npm run dev ``` 开发服务器:`http://localhost:5173` 设计器入口:`http://localhost:5173/draggable` ### 1.2 后端环境 ```bash cd vue-template-service npm install node src/index.js ``` API服务:`http://localhost:3001` ### 1.3 推荐IDE配置 - VS Code + Volar 扩展 - 启用 TypeScript 严格模式 - 配置 ESLint + Prettier --- ## 2. 代码规范 ### 2.1 TypeScript规范 ```typescript // ✅ 正确:明确定义类型 interface UserInfo { id: string name: string age: number } const user: UserInfo = { id: '1', name: 'Tom', age: 18 } // ❌ 错误:使用any const user: any = { ... } ``` ### 2.2 Vue组件规范 ```vue ``` ### 2.3 文件命名规范 | 类型 | 规范 | 示例 | |------|------|------| | Vue组件 | PascalCase | `UserProfile.vue` | | TypeScript文件 | camelCase | `dragStore.ts` | | 目录 | camelCase/PascalCase | `designComponents/` | | JSON配置 | camelCase | `index.json` | ### 2.4 目录职责 ``` draggable-panels/src/fauto/ ├── components/ # 基础UI组件(布局相关) ├── materials/ # 物料组件(可拖拽到面板的功能组件) ├── designComponents/ # 设计组件(可拖拽到页面的业务组件) ├── plugins/ # 插件系统(交互、拖拽、路径等核心逻辑) ├── stores/ # Pinia状态管理 └── types/ # 类型定义 ``` --- ## 3. Vue页面规范 ### 3.1 结构要求 **强制规则**:template第一层级**有且仅有一个el-row** ```vue ``` ```vue ``` ### 3.2 设计组件标识 页面中的设计组件需要 `data-component` 属性: ```html
``` **关键点**: - `data-component` 的值必须与设计组件的 `name` 一致 - 用于元数据面板识别组件类型并加载对应的属性schema ### 3.3 结构化路径 系统会自动为el-row/el-col生成路径ID: | 路径 | 含义 | |------|------| | `r1` | 第1个el-row | | `r1c2` | 第1个el-row的第2个el-col | | `r1c2r1` | 第1个row → 第2个col → 第1个row | | `r1c2r1c3` | 更深层嵌套... | --- ## 4. 设计组件开发 ### 4.1 创建步骤 1. 在 `draggable-panels/src/fauto/designComponents/` 创建目录 2. 添加 `index.json` 配置文件 3. 添加 `template.html` 模板文件 ### 4.2 配置文件 (index.json) ```json { "id": "MyInput", "name": "我的输入框", "icon": "✏️", "description": "自定义输入组件", "defaultSpan": 12, "metadata": { "span": { "label": "宽度", "type": "number", "min": 1, "max": 24, "target": "el-col", "attr": ":span" }, "label": { "label": "标签", "type": "text", "target": "el-form-item", "attr": "label" }, "placeholder": { "label": "占位符", "type": "text", "target": "el-input", "attr": "placeholder" }, "disabled": { "label": "禁用", "type": "boolean", "target": "el-input", "attr": "disabled" }, "size": { "label": "尺寸", "type": "select", "options": ["", "large", "default", "small"], "target": "el-input", "attr": "size" }, "textColor": { "label": "文字颜色", "type": "color", "target": "el-input", "attr": "text-color" } } } ``` ### 4.3 元数据类型 | type | 说明 | 渲染控件 | |------|------|----------| | `number` | 数字 | 数字输入框 | | `text` | 文本 | 文本输入框 | | `select` | 选择 | 下拉选择框 | | `boolean` | 布尔 | 开关/复选框 | | `color` | 颜色 | 颜色选择器 | | `columns` | 列配置 | (暂不支持) | ### 4.4 模板文件 (template.html) ```html
``` **模板规范**: - 外层必须是 `el-col` - 内层 `div` 必须有 `class="design-component"` 和 `data-component` - `data-component` 值与 `index.json` 的 `name` 一致 ### 4.5 扩展元数据类型 如需添加新的元数据类型: 1. 在 `designStore.ts` 的 `MetadataField.type` 添加类型 2. 在 `DataTable/index.vue` 添加对应的编辑控件 ```typescript // designStore.ts export interface MetadataField { type: 'text' | 'number' | 'select' | 'boolean' | 'color' | 'myNewType' // ... } ``` ```vue ``` --- ## 5. 物料组件开发 ### 5.1 创建步骤 1. 在 `draggable-panels/src/fauto/materials/` 创建目录 2. 添加 `index.vue` 组件文件 3. 添加 `index.json` 配置文件 4. 在 `materials/index.ts` 注册 ### 5.2 组件文件 (index.vue) ```vue ``` ### 5.3 配置文件 (index.json) ```json { "id": "MyMaterial", "name": "我的物料", "icon": "🔧", "description": "物料组件描述", "category": "tool", "defaultPanel": "left" } ``` ### 5.4 注册物料 ```typescript // materials/index.ts export { default as MyMaterial } from './MyMaterial/index.vue' export const materialConfigs = { // ... MyMaterial: () => import('./MyMaterial/index.json') } ``` --- ## 6. 插件开发 ### 6.1 插件位置 所有与交互、拖拽、路径相关的核心逻辑放在 `draggable-panels/src/fauto/plugins/` ### 6.2 创建新插件 ```typescript // plugins/myPlugin.ts import { defineStore } from 'pinia' import { ref, computed } from 'vue' export const useMyPlugin = defineStore('myPlugin', () => { // 状态 const state = ref(initialState) // 计算属性 const derivedValue = computed(() => ...) // 方法 const doSomething = () => { ... } return { state, derivedValue, doSomething } }) ``` ### 6.3 统一导出 ```typescript // plugins/index.ts export { useMyPlugin } from './myPlugin' ``` --- ## 7. 后端服务扩展 ### 7.1 添加新API ```javascript // vue-template-service/src/index.js app.post('/api/my-endpoint', async (req, res) => { try { const { param1, param2 } = req.body // 业务逻辑 const result = await myService(param1, param2) res.json({ success: true, data: result }) } catch (error) { console.error('[API] 错误:', error) res.status(500).json({ success: false, error: error.message }) } }) ``` ### 7.2 添加新服务函数 ```javascript // vue-template-service/src/services/templateService.js export function myNewFunction(vueContent, options) { try { // 1. 解析Vue文件 const sfcResult = parseSFC(vueContent) const templateBlock = sfcResult.descriptor.template // 2. 解析template AST const ast = parseTemplate(templateBlock.content, { comments: true, whitespace: 'preserve' }) // 3. 处理逻辑 // ... return { success: true, data: ... } } catch (error) { return { success: false, error: error.message } } } ``` --- ## 8. 常见问题与经验 ### 8.1 拖拽相关 #### 两阶段拖拽 拖拽分为源选择和目标选择两个阶段,避免误操作: ```typescript // dragStore.ts dragPhase: 'source' | 'target' // 源选择阶段:收集层级节点 // 目标选择阶段:选择放置位置 ``` #### 层级选择持久化 在目标选择阶段切换层级时,需要记住之前的选择: ```typescript // 当移动到新元素时,尝试保持相同的层级深度 if (previousSelectedIndex !== null) { selectedHierarchyIndex = Math.min(previousSelectedIndex, nodes.length - 1) } ``` ### 8.2 交互相关 #### 屏蔽浏览器右键菜单 实现自定义右键菜单时必须阻止默认行为: ```typescript const handleContextMenu = (e: MouseEvent) => { e.preventDefault() e.stopPropagation() // 显示自定义菜单 } ``` #### 多视图联动 设计中心、结构树、元数据面板需要同步选中状态: ```typescript // 使用自定义事件 window.dispatchEvent(new CustomEvent('design-component-selected', { detail: { path, componentName } })) // 其他组件监听 window.addEventListener('design-component-selected', handler) ``` ### 8.3 后端相关 #### 保持代码格式 修改Vue文件时使用字符串操作而非AST重建,保持原始格式: ```javascript // ✅ 正确:字符串替换 const newContent = content.substring(0, start) + newCode + content.substring(end) // ❌ 避免:AST重建会丢失格式 const newAST = transform(ast) const newContent = generate(newAST) ``` #### 热更新触发 修改Vue文件后触发事件让前端刷新: ```typescript window.dispatchEvent(new CustomEvent('vue-template-updated', { detail: { pagePath } })) ``` ### 8.4 性能优化 #### 防止重复绑定 使用标记属性避免重复绑定事件: ```typescript if (element.hasAttribute('data-fauto-bindend')) return element.setAttribute('data-fauto-bindend', 'true') ``` #### MutationObserver 监听DOM变化动态注入事件: ```typescript const observer = new MutationObserver((mutations) => { // 检查是否有新的el-row/el-col if (hasNewElements) { injectInteractionEvents() } }) observer.observe(container, { childList: true, subtree: true }) ``` --- ## 9. 调试技巧 ### 9.1 前端调试 ```typescript // 在关键位置添加日志 console.log('[模块名] 操作:', { data }) // 使用Vue DevTools查看Pinia状态 // 使用浏览器DevTools的Elements面板查看data-path属性 ``` ### 9.2 后端调试 ```javascript // 添加详细日志 console.log(`[API] 请求: ${req.path}`, req.body) console.log(`[Service] 处理结果:`, result) ``` ### 9.3 常用调试命令 ```bash # 查看端口占用 netstat -ano | findstr :3001 # 杀死进程 taskkill /F /PID ``` --- **文档更新时间**:2026-01-20