This commit is contained in:
wfz
2026-01-20 22:07:05 +08:00
parent bfa4e3107f
commit 842a132ec6
5 changed files with 1301 additions and 535 deletions

View File

@@ -1,6 +1,6 @@
# Vue页面可视化设计器 - 项目上下文
> **用途**AI 协作快速恢复上下文
> **用途**用于在新环境快速恢复 AI 协作上下文
> **更新时间**2026-01-20
> **项目路径**`d:/workspace/fauto-design`
@@ -8,15 +8,17 @@
## 📋 项目概述
基于 **Vue3 + TypeScript + Vite + Element Plus** 的**可视化页面设计器**通过拖拽操作直接编辑真实的Vue源文件。
这是一个基于 **Vue3 + TypeScript + Vite + Element Plus** 的**可视化页面设计器**通过拖拽操作直接编辑真实的Vue页面源文件。
### 核心特性
1. **直接解析Vue文件** - 动态扫描并渲染 `src/views` 下的页面
2. **拖拽式设计** - 将组件拖拽到页面的 el-row/el-col 上
3. **两阶段拖拽** - 源选择阶段 → 目标选择阶段
4. **智能层级选择** - 键盘 ↑↓ 切换嵌套元素层级
5. **源码实时修改** - 后端服务解析AST并修改Vue文件
1. **直接解析Vue文件** - 动态扫描并渲染`src/views`下的页面
2. **拖拽式设计** - 将设计组件拖拽到页面,支持四个方向放置
3. **源码级修改** - 拖拽操作直接修改Vue源文件支持热更新
4. **智能层级选择** - 键盘方向键切换嵌套元素层级
5. **实时视觉反馈** - 拖拽预览 + 拖放区域显示
6. **元数据编辑** - 点击组件可编辑属性(宽度、尺寸、颜色等)
7. **多种删除方式** - 右键菜单、Del键、删除图标
---
@@ -25,152 +27,215 @@
```
fauto-design/
├── draggable-panels/ # 前端项目
── src/
├── fauto/ # 🔥 设计器核心
│ ├── Designer.vue # 设计器主入口
│ ├── components/ # 基础UI组件
│ ├── materials/ # 物料组件系统
│ │ ├── DesignCenter/ # 设计中心
│ │ │ ├── InteractiveWrapper.vue # 交互注入器
│ │ │ ── DropZone.vue # 拖放指示
│ │ ├── DesignComponentList/ # 设计组件列表
│ │ └── PageManager/ # 页面管理
├── designComponents/ # 设计组件库
│ ├── plugins/ # 🔌 核心插件
│ │ ├── dragStore.ts # 拖拽状态管理
│ │ ├── interactionStore.ts
│ │ ── pathUtils.ts # 路径工具
└── stores/ # Pinia状态
└── views/ # 示例页面
── src/
├── fauto/ # 🔥 设计器核心代码
│ ├── Designer.vue # 设计器主入口
│ │ │
│ ├── components/ # 基础UI组件
│ │ ├── Header.vue # 顶部菜单栏
│ │ │ │ ├── Footer.vue # 底部状态栏
│ │ │ │ ── MainLayout.vue # 三栏布局容
│ │ ├── Panel.vue # 面板容器
│ │ └── Resizer.vue # 面板分隔器
│ ├── materials/ # 🎁 物料组件系统
│ │ ├── PageManager/ # 页面管理(树形文件选择)
│ │ ├── DesignComponentList/ # 设计组件列表
│ │ ── DesignCenter/ # 设计中心(动态渲染页面)
├── index.vue
│ │ ├── InteractiveWrapper.vue # 交互包装器
│ │ │ │ │ ├── DropZone.vue # 拖放区域指示器
│ │ │ │ │ └── DragPreview.vue # 拖拽预览
│ │ │ │ ├── TreeViewer/ # 结构树(页面结构展示)
│ │ │ │ └── DataTable/ # 元数据编辑器
│ │ │ │
│ │ │ ├── designComponents/ # 🎨 设计组件库
│ │ │ │ ├── TextInput/ # 输入框
│ │ │ │ │ ├── index.json # 组件配置+元数据schema
│ │ │ │ │ └── template.html # 组件模板
│ │ │ │ ├── RadioSelect/ # 单选器
│ │ │ │ └── GridTable/ # 表格
│ │ │ │
│ │ │ ├── plugins/ # 🔌 插件系统
│ │ │ │ ├── index.ts # 统一导出
│ │ │ │ ├── interactionStore.ts # 交互事件钩子
│ │ │ │ ├── dragStore.ts # 拖拽状态管理
│ │ │ │ └── pathUtils.ts # 结构化路径工具
│ │ │ │
│ │ │ ├── stores/ # 🗄️ Pinia状态管理
│ │ │ │ ├── panelStore.ts # 面板布局状态
│ │ │ │ ├── designStore.ts # 设计组件元数据
│ │ │ │ └── vueFileStore.ts# Vue文件选择状态
│ │ │ │
│ │ │ └── types/ # 📝 类型定义
│ │ │
│ │ └── views/ # 📄 示例页面
│ │
│ └── vite.config.ts
└── vue-template-service/ # 后端服务Node.js
└── vue-template-service/ # 🖥️ 后端服务
└── src/
├── index.js # Express API
├── index.js # Express服务入口
└── services/
└── templateService.js # Vue模板解析修改
└── templateService.js # Vue模板解析修改服务
```
---
## 🔑 核心技术要点
### 1. Vue页面规范
### 1. **两阶段拖拽机制**
**强制规则**template 第一层级**有且仅有一个 el-row**
```vue
<template>
<el-row :gutter="20">
<el-col :span="12">内容</el-col>
<el-col :span="12">
<el-row> <!-- 支持嵌套 -->
<el-col :span="24">嵌套内容</el-col>
</el-row>
</el-col>
</el-row>
</template>
```
### 2. 结构化路径ID ⭐
**格式**`r{n}c{m}...`r=row, c=col, 数字=索引从1开始
**示例**`r1c2r1c3` = 第1个row → 第2个col → 第1个row → 第3个col
### 3. 两阶段拖拽 ⭐⭐
| 阶段 | 触发 | ↑↓键功能 | 拖放方向 |
|------|------|----------|---------|
| **源选择** | 点击元素 | 切换源层级 | 不显示 |
| **目标选择** | 移到其他元素 | 切换目标层级 | 显示 |
**第一阶段(源选择)**:鼠标按下开始,收集当前位置的层级节点
**第二阶段(目标选择)**:移动到新位置,选择目标和方向
```typescript
// dragStore.ts 核心状态
dragPhase: 'source' | 'target'
confirmedSource: { path, type, element }
// dragStore.ts
startDragFromCanvas(path, type, element)
enterTargetPhase(element)
confirmDrop(pagePath) API执行移动
```
### 4. 跨类型拖放
### 2. **结构化路径ID**
- **同类型**el-row→el-row 显示上/下el-col→el-col 显示左/右
- **跨类型**el-row→el-col 或 el-col→el-row 显示"放入内部"(inside)
**格式**`r{n}c{m}r{x}c{y}...`
- `r`: el-row
- `c`: el-col
- 数字同级索引从1开始
### 5. 后端模板服务 ⭐⭐
**示例**`r1c2r1c3` 表示:
- 第1个el-row → 第2个el-col → 第1个el-row → 第3个el-col
**API**`POST http://localhost:3001/api/move-element`
### 3. **设计组件标识** ⭐
设计组件使用 `data-component` 属性标识类型:
```html
<el-col :span="12">
<div class="design-component" data-component="输入框">
<el-form-item label="文本输入">
<el-input v-model="inputValue" />
</el-form-item>
</div>
</el-col>
```
### 4. **元数据Schema定义** ⭐
设计组件的 index.json 定义可编辑属性:
```json
{
"pagePath": "views/TestPage1.vue",
"source": "r1c1",
"target": "r1c2",
"direction": "right" // top|bottom|left|right|inside
"id": "TextInput",
"name": "输入框",
"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" }
}
}
```
**技术栈**
- `@vue/compiler-sfc` - 解析Vue SFC
- `@vue/compiler-dom` - 解析template AST
- 字符串操作移动元素(保持原始格式)
---
## 🔗 后端API
| 端点 | 方法 | 功能 |
|------|------|------|
| `/api/move-element` | POST | 移动元素(画布内拖拽) |
| `/api/insert-element` | POST | 插入新元素(设计组件拖入) |
| `/api/delete-element` | POST | 删除元素 |
| `/api/element-tree` | GET | 获取页面结构树 |
| `/api/component-props` | GET | 获取组件属性值 |
| `/api/update-props` | POST | 更新组件属性值 |
---
## 🎯 数据流
## 🎯 数据流
```
用户点击元素开始拖拽
dragStore.startDragFromCanvas() → 源选择阶段
按↑↓键切换源层级
移动到其他元素 → dragStore.enterTargetPhase() → 目标选择阶段
按↑↓键切换目标层级显示DropZone
松开鼠标 → dragStore.confirmDrop()
调用后端API → templateService.moveElement()
修改Vue源文件 → 页面热更新
┌─────────────────────────────────────────────────────────────────┐
│ 用户操作 │
└───────────────────────────┬─────────────────────────────────────┘
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 页面管理器 │ │ 设计组件列表 │ │ 设计中心 │
│ (选择Vue文件) │ │ (拖拽组件) │ │ (编辑区域) │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
▼ ▼ ▼
┌───────────────────────────────────────────────────────────────┐
│ Pinia 状态管理 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ vueFileStore │ │ dragStore │ │ designStore │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└───────────────────────────┬───────────────────────────────────┘
┌───────────────────────────────────────────────────────────────┐
│ vue-template-service │
│ (Node.js后端服务) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ templateService.js - Vue模板AST解析与修改 │ │
│ └─────────────────────────────────────────────────────────┘ │
└───────────────────────────┬───────────────────────────────────┘
┌───────────────────────────────────────────────────────────────┐
│ Vue源文件 │
│ (src/views/*.vue) │
└───────────────────────────────────────────────────────────────┘
```
---
## 🛠️ 快速开始
### 启动前端
```bash
# 启动前端端口5173
cd draggable-panels
npm install
npm run dev
# 启动后端端口3001
cd vue-template-service
node src/index.js
# 访问 http://localhost:5173/draggable
```
**访问**http://localhost:5173/draggable
### 启动后端
```bash
cd vue-template-service
npm install
node src/index.js
# 服务运行在 http://localhost:3001
```
---
## 📝 关键文件
## 📝 Vue页面规范
| 文件 | 用途 |
|------|------|
| `plugins/dragStore.ts` | 拖拽状态、两阶段逻辑、层级选择 |
| `materials/DesignCenter/InteractiveWrapper.vue` | 交互注入、键盘监听、拖放确认 |
| `materials/DesignCenter/DropZone.vue` | 拖放方向指示器 |
| `vue-template-service/src/services/templateService.js` | AST解析、元素移动 |
**强制规则**template的第一层级**有且仅有一个el-row**
```vue
<template>
<el-row :gutter="20">
<el-col :span="12">
<div class="design-component" data-component="输入框">
<!-- 内容 -->
</div>
</el-col>
</el-row>
</template>
```
---
## 💡 注意事项
## 📚 相关文档
1. 拖拽时会禁用文本选择(`user-select: none`
2. 使用全局鼠标事件获取悬停位置(避免 pointer-events 问题)
3. 移动元素时保持相对缩进关系
4. 前后端都需要运行才能完成拖放后的源码修改
- **详细设计文档**`项目设计文档.md`
- **开发者指南**`DEVELOPMENT.md`
- **README**`README.md`
---
**最后更新**2026-01-20
**最后更新**2026-01-20
**AI协作建议**:优先阅读"核心技术要点"和"后端API"部分,理解系统的数据流和交互方式