Files
fauto-design/项目设计文档.md
2026-01-20 22:07:05 +08:00

424 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Vue页面可视化设计器 - 项目设计文档
## 1. 项目概述
本项目是一个基于 **Vue3 + TypeScript + Element Plus** 的可视化页面设计器通过拖拽操作直接编辑真实的Vue源文件实现低代码页面快速构建。
### 1.1 核心特性
| 特性 | 描述 |
|------|------|
| 直接解析Vue文件 | 动态渲染真实的.vue页面 |
| 源码级修改 | 拖拽操作直接修改Vue源文件 |
| 智能层级选择 | 键盘方向键切换嵌套元素层级 |
| 元数据编辑 | 可视化编辑组件属性 |
| 多视图联动 | 设计中心、结构树、元数据面板同步选中 |
| 热更新 | 修改后自动刷新预览 |
### 1.2 技术架构
```
┌─────────────────────────────────────────────────────────────────┐
│ 前端应用 (Vue3 + Vite) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 页面管理 │ │设计组件列│ │ 设计中心 │ │ 元数据 │ │
│ │ │ │表 │ │ │ │ 编辑器 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Pinia 状态管理 + 插件系统 │ │
│ │ dragStore │ interactionStore │ designStore │ vueFileStore│ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ HTTP API
┌─────────────────────────────────────────────────────────────────┐
│ 后端服务 (Node.js + Express) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ templateService - Vue模板AST解析与修改 │ │
│ │ @vue/compiler-sfc + @vue/compiler-dom │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ 文件操作
┌─────────────────────────────────────────────────────────────────┐
│ Vue源文件 (src/views/*.vue) │
└─────────────────────────────────────────────────────────────────┘
```
---
## 2. 核心模块设计
### 2.1 前端模块
#### 2.1.1 设计中心 (DesignCenter)
**职责**动态渲染选中的Vue页面注入交互事件
**核心组件**
- `index.vue` - 主容器动态加载Vue页面组件
- `InteractiveWrapper.vue` - 交互包装器,注入事件监听
- `DropZone.vue` - 拖放区域指示器
- `DragPreview.vue` - 拖拽跟随预览
**交互事件注入流程**
```typescript
// 1. 动态渲染页面组件
<component :is="selectedPageComponent" />
// 2. 挂载后扫描DOM注入事件
const injectInteractionEvents = () => {
document.querySelectorAll('.el-row, .el-col').forEach(el => {
const path = generateElementPath(el) // 生成结构化路径
bindElementEvents(el, type, path) // 绑定交互事件
})
}
// 3. MutationObserver监听DOM变化动态注入
observer.observe(container, { childList: true, subtree: true })
```
#### 2.1.2 结构树 (TreeViewer)
**职责**展示页面的el-row/el-col结构支持选中和删除
**功能**
- 树形展示页面结构
- 点击节点选中对应元素
- 拖拽节点调整顺序
- 右键菜单/删除图标/Del键删除
#### 2.1.3 元数据编辑器 (DataTable)
**职责**:展示和编辑选中组件的属性
**支持的属性类型**
- `number` - 数字输入如span宽度
- `text` - 文本输入如placeholder
- `select` - 下拉选择如size尺寸
- `boolean` - 开关切换如stripe斑马纹
- `color` - 颜色选择器
#### 2.1.4 插件系统 (plugins/)
**dragStore** - 拖拽状态管理
```typescript
interface DragStore {
// 状态
isDragging: boolean
dragPhase: 'source' | 'target' // 两阶段拖拽
dragSource: DragSource | null
hierarchyNodes: HierarchyNode[] // 层级节点列表
selectedHierarchyIndex: number // 当前选中层级
hoverDirection: Direction | null
// 方法
startDragFromCanvas(path, type, element) // 开始画布内拖拽
startDragFromComponentList(id, name, template) // 开始组件列表拖拽
enterTargetPhase(element) // 进入目标选择阶段
selectParentLevel() // 选择父级(↑键)
selectChildLevel() // 选择子级(↓键)
confirmDrop(pagePath) // 确认拖放
}
```
**interactionStore** - 交互事件钩子
```typescript
interface InteractionStore {
hoverTarget: InteractionTarget | null
selectedTarget: InteractionTarget | null
onHover(target)
onClick(target)
onLeave()
}
```
### 2.2 后端模块
#### 2.2.1 templateService
**职责**解析Vue文件执行结构修改
**核心函数**
| 函数 | 功能 |
|------|------|
| `moveElement(vueContent, options)` | 移动元素到新位置 |
| `insertElement(vueContent, options)` | 插入新元素 |
| `deleteElement(vueContent, elementPath)` | 删除元素 |
| `parseElementTree(vueContent)` | 解析页面结构树 |
| `parseComponentProps(vueContent, path)` | 获取组件属性 |
| `updateComponentProps(vueContent, path, updates)` | 更新组件属性 |
**技术实现**
```javascript
// 使用 @vue/compiler-sfc 解析Vue文件
import { parse as parseSFC } from '@vue/compiler-sfc'
// 使用 @vue/compiler-dom 解析template获取AST
import { parse as parseTemplate } from '@vue/compiler-dom'
// 通过AST定位元素使用字符串操作修改保持原始格式
```
---
## 3. 数据结构设计
### 3.1 结构化路径
**格式**`r{n}c{m}r{x}c{y}...`
| 前缀 | 含义 |
|------|------|
| r | el-row |
| c | el-col |
| 数字 | 同级元素中的索引从1开始 |
**示例**`r1c2r1` = 第1个row → 第2个col → 第1个row
### 3.2 设计组件配置
```json
{
"id": "TextInput",
"name": "输入框",
"icon": "✏️",
"description": "用于输入文本内容的表单组件",
"defaultSpan": 12,
"metadata": {
"span": {
"label": "宽度",
"type": "number",
"min": 1,
"max": 24,
"target": "el-col",
"attr": ":span"
},
"placeholder": {
"label": "占位符",
"type": "text",
"target": "el-input",
"attr": "placeholder"
}
}
}
```
### 3.3 设计组件模板
```html
<el-col :span="12">
<div class="design-component design-text-input" data-component="输入框">
<el-form-item label="文本输入">
<el-input v-model="inputValue" placeholder="请输入内容"></el-input>
</el-form-item>
</div>
</el-col>
```
**关键点**
- 外层必须是 `el-col`
- 内层 `div` 必须有 `data-component` 属性标识组件类型
- 使用 `class="design-component"` 标识设计组件
---
## 4. API设计
### 4.1 元素操作API
#### 移动元素
```
POST /api/move-element
Body: {
"pagePath": "D:/workspace/.../TestPage1.vue",
"source": {
"type": "canvas-element",
"path": "r1c1",
"elementType": "ec"
},
"targetPath": "r1c2",
"targetType": "ec",
"direction": "right" // top|bottom|left|right|inside
}
```
#### 插入元素
```
POST /api/insert-element
Body: {
"pagePath": "...",
"templateContent": "<el-col :span=\"12\">...</el-col>",
"targetPath": "r1c1",
"direction": "right"
}
```
#### 删除元素
```
POST /api/delete-element
Body: {
"pagePath": "...",
"elementPath": "r1c2"
}
```
### 4.2 属性操作API
#### 获取组件属性
```
GET /api/component-props?pagePath=...&elementPath=r1c1
Response: {
"success": true,
"componentId": "输入框",
"props": {
"span": 12,
"el-input:placeholder": "请输入"
}
}
```
#### 更新组件属性
```
POST /api/update-props
Body: {
"pagePath": "...",
"elementPath": "r1c1",
"updates": {
"span": 8,
"el-input:placeholder": "新占位符"
}
}
```
### 4.3 结构查询API
#### 获取页面结构树
```
GET /api/element-tree?pagePath=...
Response: {
"success": true,
"tree": [
{
"type": "row",
"path": "r1",
"label": "el-row",
"children": [
{
"type": "col",
"path": "r1c1",
"componentName": "输入框",
"children": []
}
]
}
]
}
```
---
## 5. 交互设计
### 5.1 拖拽流程
```
1. 用户开始拖拽(组件列表/画布元素)
2. 进入源选择阶段,收集层级节点
3. 移动到目标位置,进入目标选择阶段
4. 显示DropZone上/下/左/右/放入)
5. 用户点击方向确认拖放
6. 调用后端API修改源文件
7. 触发vue-template-updated事件
8. 前端刷新页面和结构树
```
### 5.2 层级选择
当鼠标悬停在嵌套元素上时(如`r1c1r1c1`
- **默认选中**最深层级r1c1r1c1
- **↑键**切换到父级r1c1r1 → r1c1 → r1
- **↓键**:切换到子级
- **Esc**:取消拖拽
### 5.3 多视图联动
- 点击**设计中心**元素 → 结构树高亮 + 元数据面板更新
- 点击**结构树**节点 → 设计中心高亮 + 元数据面板更新
- **元数据面板**修改 → 源文件更新 → 设计中心刷新
---
## 6. 扩展指南
### 6.1 添加设计组件
1.`src/fauto/designComponents/` 创建目录
2. 添加 `index.json`(配置+元数据schema
3. 添加 `template.html`(组件模板)
4. 自动在组件列表显示
### 6.2 添加物料组件
1.`src/fauto/materials/` 创建目录
2. 添加 `index.vue`(组件实现)
3. 添加 `index.json`(配置信息)
4.`materials/index.ts` 注册
### 6.3 扩展元数据类型
`designStore.ts``MetadataField` 接口添加新类型,并在 `DataTable/index.vue` 添加对应的编辑控件。
---
## 7. 技术规范
### 7.1 Vue页面规范
```vue
<template>
<!-- 第一层级必须且只能有一个el-row -->
<el-row :gutter="20">
<el-col :span="24">
<!-- 设计组件必须有data-component属性 -->
<div class="design-component" data-component="组件名">
<!-- 组件内容 -->
</div>
</el-col>
</el-row>
</template>
```
### 7.2 代码规范
- TypeScript 严格模式
- Composition API 组织代码
- Props 必须定义类型
- 样式使用 scoped
- 插件代码放 `fauto/plugins/`
---
## 8. 版本信息
- **前端框架**: Vue 3.5.24
- **构建工具**: Vite 7.3.0
- **状态管理**: Pinia 3.0.4
- **UI框架**: Element Plus
- **后端运行时**: Node.js
- **模板解析**: @vue/compiler-sfc, @vue/compiler-dom
---
**文档更新时间**2026-01-20