From f858f69daa61fdf1e35863b1e3c34c671a66af53 Mon Sep 17 00:00:00 2001 From: fangzhenwu <1040079213@qq.com> Date: Sat, 20 Dec 2025 23:16:23 +0800 Subject: [PATCH] 23 --- draggable-panels/config.json | 16 +- draggable-panels/design-state.json | 28 ++- draggable-panels/package-lock.json | 22 ++ draggable-panels/package.json | 1 + draggable-panels/src/App.vue | 29 +-- draggable-panels/src/fauto/Designer.vue | 34 +++ .../src/{ => fauto}/components/Footer.vue | 0 .../src/{ => fauto}/components/Header.vue | 0 .../src/{ => fauto}/components/HelloWorld.vue | 0 .../src/{ => fauto}/components/MainLayout.vue | 0 .../src/{ => fauto}/components/Panel.vue | 0 .../src/{ => fauto}/components/Resizer.vue | 0 .../designComponents/GridTable/index.json | 0 .../designComponents/GridTable/index.vue | 0 .../designComponents/RadioSelect/index.json | 0 .../designComponents/RadioSelect/index.vue | 0 .../designComponents/TextInput/index.json | 0 .../designComponents/TextInput/index.vue | 0 .../materials/DataTable/index.json | 0 .../{ => fauto}/materials/DataTable/index.vue | 0 .../materials/DesignCenter/index.json | 0 .../materials/DesignCenter/index.vue | 21 +- .../materials/DesignComponentList/index.json | 0 .../materials/DesignComponentList/index.vue | 0 .../materials/TestWidget1/index.json | 0 .../materials/TestWidget1/index.vue | 0 .../materials/TestWidget2/index.json | 0 .../materials/TestWidget2/index.vue | 0 .../materials/TestWidget3/index.json | 0 .../materials/TestWidget3/index.vue | 0 .../materials/TextEditor/index.json | 0 .../materials/TextEditor/index.vue | 0 .../materials/TreeViewer/index.json | 0 .../materials/TreeViewer/index.vue | 16 +- draggable-panels/src/fauto/materials/index.ts | 43 ++++ .../src/{ => fauto}/stores/designStore.ts | 27 ++- .../src/{ => fauto}/stores/panelStore.ts | 0 .../src/{ => fauto}/types/index.ts | 0 draggable-panels/src/main.ts | 2 + draggable-panels/src/materials/index.ts | 46 ---- draggable-panels/src/router.ts | 23 ++ draggable-panels/src/views/HelloWorld.vue | 68 ++++++ draggable-panels/项目设计文档.md | 199 ++++++++++++++++++ 43 files changed, 476 insertions(+), 99 deletions(-) create mode 100644 draggable-panels/src/fauto/Designer.vue rename draggable-panels/src/{ => fauto}/components/Footer.vue (100%) rename draggable-panels/src/{ => fauto}/components/Header.vue (100%) rename draggable-panels/src/{ => fauto}/components/HelloWorld.vue (100%) rename draggable-panels/src/{ => fauto}/components/MainLayout.vue (100%) rename draggable-panels/src/{ => fauto}/components/Panel.vue (100%) rename draggable-panels/src/{ => fauto}/components/Resizer.vue (100%) rename draggable-panels/src/{ => fauto}/designComponents/GridTable/index.json (100%) rename draggable-panels/src/{ => fauto}/designComponents/GridTable/index.vue (100%) rename draggable-panels/src/{ => fauto}/designComponents/RadioSelect/index.json (100%) rename draggable-panels/src/{ => fauto}/designComponents/RadioSelect/index.vue (100%) rename draggable-panels/src/{ => fauto}/designComponents/TextInput/index.json (100%) rename draggable-panels/src/{ => fauto}/designComponents/TextInput/index.vue (100%) rename draggable-panels/src/{ => fauto}/materials/DataTable/index.json (100%) rename draggable-panels/src/{ => fauto}/materials/DataTable/index.vue (100%) rename draggable-panels/src/{ => fauto}/materials/DesignCenter/index.json (100%) rename draggable-panels/src/{ => fauto}/materials/DesignCenter/index.vue (82%) rename draggable-panels/src/{ => fauto}/materials/DesignComponentList/index.json (100%) rename draggable-panels/src/{ => fauto}/materials/DesignComponentList/index.vue (100%) rename draggable-panels/src/{ => fauto}/materials/TestWidget1/index.json (100%) rename draggable-panels/src/{ => fauto}/materials/TestWidget1/index.vue (100%) rename draggable-panels/src/{ => fauto}/materials/TestWidget2/index.json (100%) rename draggable-panels/src/{ => fauto}/materials/TestWidget2/index.vue (100%) rename draggable-panels/src/{ => fauto}/materials/TestWidget3/index.json (100%) rename draggable-panels/src/{ => fauto}/materials/TestWidget3/index.vue (100%) rename draggable-panels/src/{ => fauto}/materials/TextEditor/index.json (100%) rename draggable-panels/src/{ => fauto}/materials/TextEditor/index.vue (100%) rename draggable-panels/src/{ => fauto}/materials/TreeViewer/index.json (100%) rename draggable-panels/src/{ => fauto}/materials/TreeViewer/index.vue (89%) create mode 100644 draggable-panels/src/fauto/materials/index.ts rename draggable-panels/src/{ => fauto}/stores/designStore.ts (84%) rename draggable-panels/src/{ => fauto}/stores/panelStore.ts (100%) rename draggable-panels/src/{ => fauto}/types/index.ts (100%) delete mode 100644 draggable-panels/src/materials/index.ts create mode 100644 draggable-panels/src/router.ts create mode 100644 draggable-panels/src/views/HelloWorld.vue create mode 100644 draggable-panels/项目设计文档.md diff --git a/draggable-panels/config.json b/draggable-panels/config.json index 797b04a..bcb2d46 100644 --- a/draggable-panels/config.json +++ b/draggable-panels/config.json @@ -8,6 +8,12 @@ "title": "设计组件列表", "content": "新窗口内容", "materialId": "DesignComponentList" + }, + { + "id": "78ikdz5", + "title": "测试组件B", + "content": "新窗口内容", + "materialId": "TestWidget2" } ], "activeTabId": "up60643" @@ -20,6 +26,12 @@ "title": "设计中心", "content": "新窗口内容", "materialId": "DesignCenter" + }, + { + "id": "rdp9iuv", + "title": "测试组件A", + "content": "新窗口内容", + "materialId": "TestWidget1" } ], "activeTabId": "j70ckww" @@ -132,8 +144,8 @@ } } ], - "activeTabId": "mxfx11j" + "activeTabId": "vrh9bl2" } }, - "lastUpdated": "2025-12-20T13:24:03.895Z" + "lastUpdated": "2025-12-20T14:50:20.652Z" } \ No newline at end of file diff --git a/draggable-panels/design-state.json b/draggable-panels/design-state.json index 9c7093f..f8ef0d0 100644 --- a/draggable-panels/design-state.json +++ b/draggable-panels/design-state.json @@ -12,6 +12,16 @@ ] } }, + { + "id": "nx1ns6t", + "componentId": "TextInput", + "name": "文本输入框 1", + "props": { + "label": "标签111", + "width": 500, + "maxLength": 100 + } + }, { "id": "xazr6j9", "componentId": "GridTable", @@ -30,16 +40,20 @@ } }, { - "id": "nx1ns6t", - "componentId": "TextInput", - "name": "文本输入框 1", + "id": "sc9viyu", + "componentId": "GridTable", + "name": "表格 2", "props": { - "label": "标签名称", - "width": 500, - "maxLength": 100 + "rows": 3, + "columns": 3, + "headers": [ + "列1", + "列2", + "列3" + ] } } ], "selectedId": "xazr6j9", - "lastUpdated": "2025-12-20T13:24:06.541Z" + "lastUpdated": "2025-12-20T14:50:43.062Z" } \ No newline at end of file diff --git a/draggable-panels/package-lock.json b/draggable-panels/package-lock.json index a9ce785..b60d0cb 100644 --- a/draggable-panels/package-lock.json +++ b/draggable-panels/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "pinia": "^3.0.4", "vue": "^3.5.24", + "vue-router": "^4.6.4", "vuedraggable": "^4.1.0" }, "devDependencies": { @@ -1563,6 +1564,27 @@ } } }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, "node_modules/vue-tsc": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.1.8.tgz", diff --git a/draggable-panels/package.json b/draggable-panels/package.json index d2c6257..6add1be 100644 --- a/draggable-panels/package.json +++ b/draggable-panels/package.json @@ -11,6 +11,7 @@ "dependencies": { "pinia": "^3.0.4", "vue": "^3.5.24", + "vue-router": "^4.6.4", "vuedraggable": "^4.1.0" }, "devDependencies": { diff --git a/draggable-panels/src/App.vue b/draggable-panels/src/App.vue index 9a0bab2..1247529 100644 --- a/draggable-panels/src/App.vue +++ b/draggable-panels/src/App.vue @@ -1,34 +1,11 @@ diff --git a/draggable-panels/src/fauto/Designer.vue b/draggable-panels/src/fauto/Designer.vue new file mode 100644 index 0000000..fb1ea6b --- /dev/null +++ b/draggable-panels/src/fauto/Designer.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/draggable-panels/src/components/Footer.vue b/draggable-panels/src/fauto/components/Footer.vue similarity index 100% rename from draggable-panels/src/components/Footer.vue rename to draggable-panels/src/fauto/components/Footer.vue diff --git a/draggable-panels/src/components/Header.vue b/draggable-panels/src/fauto/components/Header.vue similarity index 100% rename from draggable-panels/src/components/Header.vue rename to draggable-panels/src/fauto/components/Header.vue diff --git a/draggable-panels/src/components/HelloWorld.vue b/draggable-panels/src/fauto/components/HelloWorld.vue similarity index 100% rename from draggable-panels/src/components/HelloWorld.vue rename to draggable-panels/src/fauto/components/HelloWorld.vue diff --git a/draggable-panels/src/components/MainLayout.vue b/draggable-panels/src/fauto/components/MainLayout.vue similarity index 100% rename from draggable-panels/src/components/MainLayout.vue rename to draggable-panels/src/fauto/components/MainLayout.vue diff --git a/draggable-panels/src/components/Panel.vue b/draggable-panels/src/fauto/components/Panel.vue similarity index 100% rename from draggable-panels/src/components/Panel.vue rename to draggable-panels/src/fauto/components/Panel.vue diff --git a/draggable-panels/src/components/Resizer.vue b/draggable-panels/src/fauto/components/Resizer.vue similarity index 100% rename from draggable-panels/src/components/Resizer.vue rename to draggable-panels/src/fauto/components/Resizer.vue diff --git a/draggable-panels/src/designComponents/GridTable/index.json b/draggable-panels/src/fauto/designComponents/GridTable/index.json similarity index 100% rename from draggable-panels/src/designComponents/GridTable/index.json rename to draggable-panels/src/fauto/designComponents/GridTable/index.json diff --git a/draggable-panels/src/designComponents/GridTable/index.vue b/draggable-panels/src/fauto/designComponents/GridTable/index.vue similarity index 100% rename from draggable-panels/src/designComponents/GridTable/index.vue rename to draggable-panels/src/fauto/designComponents/GridTable/index.vue diff --git a/draggable-panels/src/designComponents/RadioSelect/index.json b/draggable-panels/src/fauto/designComponents/RadioSelect/index.json similarity index 100% rename from draggable-panels/src/designComponents/RadioSelect/index.json rename to draggable-panels/src/fauto/designComponents/RadioSelect/index.json diff --git a/draggable-panels/src/designComponents/RadioSelect/index.vue b/draggable-panels/src/fauto/designComponents/RadioSelect/index.vue similarity index 100% rename from draggable-panels/src/designComponents/RadioSelect/index.vue rename to draggable-panels/src/fauto/designComponents/RadioSelect/index.vue diff --git a/draggable-panels/src/designComponents/TextInput/index.json b/draggable-panels/src/fauto/designComponents/TextInput/index.json similarity index 100% rename from draggable-panels/src/designComponents/TextInput/index.json rename to draggable-panels/src/fauto/designComponents/TextInput/index.json diff --git a/draggable-panels/src/designComponents/TextInput/index.vue b/draggable-panels/src/fauto/designComponents/TextInput/index.vue similarity index 100% rename from draggable-panels/src/designComponents/TextInput/index.vue rename to draggable-panels/src/fauto/designComponents/TextInput/index.vue diff --git a/draggable-panels/src/materials/DataTable/index.json b/draggable-panels/src/fauto/materials/DataTable/index.json similarity index 100% rename from draggable-panels/src/materials/DataTable/index.json rename to draggable-panels/src/fauto/materials/DataTable/index.json diff --git a/draggable-panels/src/materials/DataTable/index.vue b/draggable-panels/src/fauto/materials/DataTable/index.vue similarity index 100% rename from draggable-panels/src/materials/DataTable/index.vue rename to draggable-panels/src/fauto/materials/DataTable/index.vue diff --git a/draggable-panels/src/materials/DesignCenter/index.json b/draggable-panels/src/fauto/materials/DesignCenter/index.json similarity index 100% rename from draggable-panels/src/materials/DesignCenter/index.json rename to draggable-panels/src/fauto/materials/DesignCenter/index.json diff --git a/draggable-panels/src/materials/DesignCenter/index.vue b/draggable-panels/src/fauto/materials/DesignCenter/index.vue similarity index 82% rename from draggable-panels/src/materials/DesignCenter/index.vue rename to draggable-panels/src/fauto/materials/DesignCenter/index.vue index aa3cbb0..cc2db29 100644 --- a/draggable-panels/src/materials/DesignCenter/index.vue +++ b/draggable-panels/src/fauto/materials/DesignCenter/index.vue @@ -1,15 +1,24 @@ + + + + diff --git a/draggable-panels/项目设计文档.md b/draggable-panels/项目设计文档.md new file mode 100644 index 0000000..4ba1ab1 --- /dev/null +++ b/draggable-panels/项目设计文档.md @@ -0,0 +1,199 @@ +# 可拖拽子窗口项目设计文档 + +## 项目概述 + +本项目是一个基于 Vite + Vue3 + TypeScript 的可拖拽子窗口系统,模仿 IDE(如 IntelliJ IDEA、Visual Studio)的界面设计,提供多区域可拖拽的窗口管理功能。 + +## 技术架构 + +### 核心技术栈 +- **构建工具**: Vite 7.3.0 +- **前端框架**: Vue 3.5.24 (Composition API) +- **状态管理**: Pinia 3.0.4 +- **类型系统**: TypeScript +- **拖拽库**: vuedraggable 4.1.0 +- **样式**: CSS Modules + Scoped Styles + +### 项目结构 +``` +src/ +├── assets/ # 静态资源 +├── components/ # 核心UI组件 +│ ├── Header.vue # 顶部菜单栏 +│ ├── Footer.vue # 底部状态栏 +│ ├── MainLayout.vue # 主布局容器 +│ ├── Panel.vue # 面板容器 +│ └── Resizer.vue # 面板分隔器 +├── materials/ # 物料组件系统 +│ ├── index.ts # 物料组件注册中心 +│ ├── TextEditor/ # 文本编辑器 +│ ├── TreeViewer/ # 树形展示器 +│ ├── DataTable/ # 数据表格 +│ ├── TestWidget*/ # 测试组件 +│ ├── DesignComponentList/ # 设计组件列表 +│ └── DesignCenter/ # 设计中心 +├── designComponents/ # 设计组件库 +│ ├── TextInput/ # 文本输入框 +│ ├── RadioSelect/ # 单选器 +│ └── GridTable/ # 表格组件 +├── stores/ # 状态管理 +│ ├── panelStore.ts # 面板布局状态 +│ └── designStore.ts # 设计中心状态 +├── types/ # TypeScript 类型定义 +└── App.vue # 应用入口 +``` + +## 核心功能模块 + +### 1. 面板系统 (Panel System) + +#### 布局结构 +- **Header**: 固定顶部,包含菜单和新增窗口按钮 +- **MainLayout**: 三区域布局(左/中/右) +- **Panel**: 可拖拽的面板容器 +- **Footer**: 固定底部,显示时间和状态信息 + +#### 拖拽实现 +使用 `vuedraggable` 库实现跨面板的 Tab 拖拽: +```vue + +``` + +### 2. 物料组件系统 (Material System) + +#### 规范标准 +遵循统一的物料组件规范: +1. 每个组件独立文件夹 +2. 包含 `index.vue`(组件实现)和 `index.json`(元数据) +3. `index.json` 定义:名称、描述、属性及默认值 + +#### 组件状态管理 +- 使用 `materialState` 属性传递组件状态 +- 通过 `update:state` 事件实现状态更新 +- 物料组件状态独立存储,组件关闭后状态仍保留 + +#### 状态持久化 +通过自定义 Vite 插件实现 API 中间件: +- `/api/config`: 布局配置读写 +- `/api/material-states`: 物料组件状态读写 +- `/api/design-components`: 设计组件元数据读取 +- `/api/design-state`: 设计中心状态读写 + +### 3. 设计组件系统 (Design System) + +#### 组件构成 +1. **设计组件库** (`designComponents/`) + - TextInput: 文本输入框(属性:label, width, maxLength) + - RadioSelect: 单选器(属性:options) + - GridTable: 表格(属性:rows, columns, headers) + +2. **物料组件** + - DesignComponentList: 展示可用设计组件 + - DesignCenter: 展示已添加的设计组件实例 + - TreeViewer: 展示设计中心组件列表(支持拖拽排序) + - DataTable: 展示选中组件的属性(支持编辑) + +#### 跨组件联动机制 +1. 点击 DesignComponentList 中的组件添加到 DesignCenter +2. 点击 DesignCenter 中的组件,在 DataTable 中展示其属性 +3. 在 TreeViewer 中拖拽组件调整 DesignCenter 的顺序 +4. 在 DataTable 中双击属性值进行编辑 + +## 状态管理设计 + +### PanelStore (面板状态) +管理整个应用的布局和物料组件状态: +- `layout`: 三区域面板配置 +- `materialStates`: 物料组件状态独立存储 +- 提供 Tab 操作 API(添加、关闭、移动、激活) + +### DesignStore (设计中心状态) +管理设计组件系统的状态: +- `components`: 已添加的设计组件实例列表 +- `selectedId`: 当前选中的组件实例ID +- `componentMetas`: 设计组件元数据缓存 + +## 实现细节 + +### 1. 拖拽功能优化 +- 使用 `:list` 属性而非 `v-model` 解决拖拽位置问题 +- 实现跨面板 Tab 拖拽 +- 面板宽度可调整(通过 Resizer 组件) + +### 2. 状态持久化策略 +- 布局配置和物料状态分别存储 +- 使用防抖机制避免频繁保存(TextEditor 500ms) +- 组件移除后状态仍保留 + +### 3. 组件通信机制 +- 父子组件:Props / Events +- 兄弟组件:通过 Pinia Store +- 物料组件:`materialState` / `update:state` + +### 4. 性能优化 +- 使用 `defineAsyncComponent` 异步加载物料组件 +- 使用 `markRaw` 避免不必要的响应式转换 +- 使用 `computed` 缓存派生数据 + +## API 设计 + +### 配置管理 API +``` +GET /api/config # 获取布局配置 +POST /api/config # 保存布局配置 +GET /api/material-states # 获取物料组件状态 +POST /api/material-states # 保存物料组件状态 +``` + +### 设计系统 API +``` +GET /api/design-components # 获取设计组件元数据 +GET /api/design-state # 获取设计中心状态 +POST /api/design-state # 保存设计中心状态 +``` + +## 开发规范 + +### 代码规范 +1. 使用 TypeScript 严格模式 +2. 组件 Props 必须明确定义类型 +3. 使用 Composition API 组织代码逻辑 +4. 样式使用 scoped 避免全局污染 + +### 组件开发规范 +1. 遵循物料组件标准化规范 +2. 状态通过 `materialState` 接收,通过 `update:state` 更新 +3. 实现防抖保存机制避免频繁 IO +4. 提供清晰的组件文档(index.json) + +### 状态管理规范 +1. 使用 Pinia 进行全局状态管理 +2. 状态变更必须通过 Store 的方法 +3. 复杂状态逻辑封装在 Store 内部 +4. 状态持久化与 UI 逻辑分离 + +## 扩展性设计 + +### 新增物料组件 +1. 在 `materials/` 目录下创建组件文件夹 +2. 实现 `index.vue` 和 `index.json` +3. 在 `materials/index.ts` 中注册组件 + +### 新增设计组件 +1. 在 `designComponents/` 目录下创建组件文件夹 +2. 实现 `index.vue` 和 `index.json` +3. 在 DesignComponentList 中会自动显示 + +### 功能扩展 +1. 面板系统支持更多布局模式 +2. 物料组件支持更多交互类型 +3. 设计系统支持更复杂的属性编辑器 + +## 总结 + +本项目实现了完整的可拖拽子窗口系统,具备良好的架构设计和扩展性。通过物料组件系统和设计组件系统的分离,既满足了基础的窗口管理需求,又提供了高级的设计能力。状态持久化机制确保了用户体验的连续性,而规范化的开发流程保证了项目的可维护性。 \ No newline at end of file