feat: add geometric optimization support for selected subassembly
This commit is contained in:
parent
04532fd42a
commit
642c9a3891
@ -11,7 +11,11 @@
|
|||||||
"Bash(do echo \"=== $dir ===\")",
|
"Bash(do echo \"=== $dir ===\")",
|
||||||
"Bash(ls:*)",
|
"Bash(ls:*)",
|
||||||
"mcp__context7__resolve-library-id",
|
"mcp__context7__resolve-library-id",
|
||||||
"mcp__context7__get-library-docs"
|
"mcp__context7__get-library-docs",
|
||||||
|
"WebSearch",
|
||||||
|
"mcp__chrome-devtools__list_pages",
|
||||||
|
"mcp__chrome-devtools__navigate_page",
|
||||||
|
"mcp__chrome-devtools__take_snapshot"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": [],
|
"ask": [],
|
||||||
@ -19,4 +23,4 @@
|
|||||||
"D:\\App\\vue\\Miany"
|
"D:\\App\\vue\\Miany"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
109
docs/frontend-technical-overview.md
Normal file
109
docs/frontend-technical-overview.md
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# 前端技术路线文档
|
||||||
|
|
||||||
|
## 1. 项目概述
|
||||||
|
- **框架基线**:基于 `Vue 3` + Composition API 构建的单页应用,入口由 `src/main.js` 创建并挂载 `App.vue`。
|
||||||
|
- **运行模式**:采用 `Vite` 作为开发服务器与构建工具,统一在 `config/vite.config.js` 配置,脚本通过 `npm run dev/build/preview` 调用。
|
||||||
|
- **部署目标**:面向工业 CAD 模型统一管理平台的前端界面,所有业务逻辑围绕 CAD 连接、模型查看、分析工具与日志监控展开。
|
||||||
|
|
||||||
|
## 2. 应用层次结构
|
||||||
|
### 2.1 启动流程
|
||||||
|
1. `main.js` 创建应用实例并加载全局依赖:`Pinia`、`Vue Router`、`Element Plus`。
|
||||||
|
2. 初始化认证状态 (`useAuthStore().initAuth()`),确保刷新后可以恢复登录信息。
|
||||||
|
3. 启动 WebSocket 服务 (`websocketService.connect()`),为后续日志与状态同步提供实时通道。
|
||||||
|
4. 挂载根组件 `App.vue`,其模板内仅渲染 `<router-view />`,由路由控制页面结构。
|
||||||
|
|
||||||
|
### 2.2 路由与页面
|
||||||
|
- 使用 `Vue Router 4`(Hash 模式)管理页面,路由定义于 `src/router/index.js`。
|
||||||
|
- 主要路由:`/login`(登录页)、`/dashboard`(主控制台),根路径重定向到仪表板。
|
||||||
|
- 全局前置守卫根据 `meta.requiresAuth` 校验登录状态,并同步浏览器标题。
|
||||||
|
|
||||||
|
### 2.3 主场景组织
|
||||||
|
- `DashboardView.vue` 作为仪表板容器,组合 `MainLayout` 布局,并通过动态组件与 `KeepAlive` 控制页面切换。
|
||||||
|
- 页面组件映射在本地 `pageComponentMap` 中,根据 `PAGE_TYPES`(`src/config/pages.js`)选择展示模块。
|
||||||
|
- 关键子组件:
|
||||||
|
- `AppHeader` 负责页面切换与信息面板控制。
|
||||||
|
- `CadSidebar` 管理各 CAD 软件连接入口。
|
||||||
|
- `InfoManagementPanel` 展示实时日志、状态信息。
|
||||||
|
- `components/pages` 目录承载具体业务页面(模型库、分析、导出、查看器等)。
|
||||||
|
|
||||||
|
## 3. 状态管理
|
||||||
|
- 统一使用 `Pinia`,入口在 `main.js` 注册。
|
||||||
|
- Store 设计遵循「只持久化状态,不处理 API 调用」原则。
|
||||||
|
|
||||||
|
### 3.1 认证状态 (`src/stores/auth.js`)
|
||||||
|
- 存储当前用户、token、加载状态与错误信息。
|
||||||
|
- 提供登录、登出、token 校验、错误清理等方法。
|
||||||
|
- 登录逻辑支持模拟异步,后续可平滑接入真实 API。
|
||||||
|
- 与本地存储联动,刷新后通过 `initAuth()` 恢复状态。
|
||||||
|
|
||||||
|
### 3.2 CAD 状态 (`src/stores/cad.js`)
|
||||||
|
- 根据 `config/cad.js` 中的 CAD 定义初始化连接状态列表。
|
||||||
|
- 维持单一连接原则:`setCADConnection` 会在连接新软件前断开其他连接。
|
||||||
|
- 暴露当前连接的软件信息、可显示 CAD 列表、项目名称等状态。
|
||||||
|
- 提供功能支持检查 (`cadSupportsFeature`) 与连接中状态更新等能力。
|
||||||
|
|
||||||
|
## 4. 配置体系
|
||||||
|
- 所有业务配置集中在 `src/config`:
|
||||||
|
- `cad.js`:CAD 软件定义、API 端点、通知、WebSocket、导出格式与默认参数;同时提供 URL 构建、功能支持判断等工具函数。
|
||||||
|
- `pages.js`:统一的页面类型常量与权限要求,供仪表板和导航模块引用。
|
||||||
|
- 其他配置文件(如 `auth`)为 Store 提供默认值、校验规则和超时设置。
|
||||||
|
|
||||||
|
## 5. 通信与服务层
|
||||||
|
### 5.1 HTTP 客户端 (`src/services/apiClient.js`)
|
||||||
|
- 基于 `fetch` 的统一封装,内置请求/响应拦截、Loading 遮罩、Element Plus 通知、操作日志同步与错误处理。
|
||||||
|
- 利用 `PostProcessManager` 组织后处理钩子:
|
||||||
|
- 成功/失败后自动弹出通知。
|
||||||
|
- 将操作日志通过 `websocketService.logOperation` 推送到后台,实现前后端日志统一。
|
||||||
|
- 提供 `get/post/put/delete` 便捷方法,默认读取 `config/cad.js` 中的请求头、超时等配置。
|
||||||
|
|
||||||
|
### 5.2 WebSocket 服务 (`src/services/websocketService.js`)
|
||||||
|
- 管理实时连接、自动重连、心跳以及后台消息解析。
|
||||||
|
- 维护软件列表、操作日志、统计信息等实时状态,并通过事件订阅模式向组件广播。
|
||||||
|
- 支持后台命令(启动/停止/重启软件、查询日志等)与操作记录上报。
|
||||||
|
- 登录用户信息会动态带入连接参数和日志上报,确保后台可追踪责任主体。
|
||||||
|
|
||||||
|
## 6. UI 与样式体系
|
||||||
|
- UI 组件库:全局注册 `Element Plus`,结合自研组件完成业务场景搭建。
|
||||||
|
- 样式策略:在 `src/assets/styles/theme.css` 定义 CSS 变量与通用样式,`App.vue` 导入后覆盖全局;组件内尽量使用作用域样式或复用变量,保持视觉一致性。
|
||||||
|
- 主题与布局:
|
||||||
|
- `layout` 目录包含主框架组件(头部、侧边、布局容器)。
|
||||||
|
- `pages` 目录按业务功能拆分子页面,保持单一职责。
|
||||||
|
- `model` 目录存放各 CAD 查看器,遵循统一的主题变量与交互规范。
|
||||||
|
|
||||||
|
## 7. 目录结构概览
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── assets/ # 静态资源与全局样式
|
||||||
|
├── components/
|
||||||
|
│ ├── layout/ # 主布局与导航组件
|
||||||
|
│ ├── model/ # 针对 CAD 的模型查看器
|
||||||
|
│ ├── pages/ # 业务页面碎片,按 PAGE_TYPES 分类
|
||||||
|
│ └── ui/ # 通用 UI 组件(树形节点等)
|
||||||
|
├── config/ # 统一配置中心(CAD、页面、认证等)
|
||||||
|
├── router/ # 路由配置与守卫
|
||||||
|
├── services/ # HTTP、WebSocket、业务服务封装
|
||||||
|
├── stores/ # Pinia Store(认证、CAD 状态等)
|
||||||
|
├── utils/ # 工具函数与日志封装
|
||||||
|
└── views/ # 路由级页面容器(Dashboard、Login 等)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 数据与事件流
|
||||||
|
1. 用户通过 `CadSidebar` 发起连接请求,组件内调用相应服务(例如 `apiClient` + `config/cad.js` 构建 URL)。
|
||||||
|
2. API 返回后,组件根据结果调用 `cadStore.setCADConnection` 更新全局状态,并向父组件触发事件以切换页面或加载数据。
|
||||||
|
3. `apiClient` 拦截器自动发送 Element Plus 通知,并通过 WebSocket 记录操作日志;WebSocket 后台返回的最新状态又会驱动 `InfoManagementPanel` 更新展示。
|
||||||
|
4. 所有跨组件通信优先使用事件 (`emit`) 与 Pinia 状态,避免组件间直接耦合。
|
||||||
|
|
||||||
|
## 9. 构建与质量保障
|
||||||
|
- `package.json` 中定义脚本:
|
||||||
|
- `npm run dev`:开发模式。
|
||||||
|
- `npm run build`:生产构建。
|
||||||
|
- `npm run preview`:本地预览构建结果。
|
||||||
|
- `npm run lint`:执行 ESLint(配置位于 `config/eslint.config.js`),自动修复常见问题。
|
||||||
|
- `npm run format`:根据 `config/.prettierrc.json` 格式化 `src/` 目录。
|
||||||
|
- 推荐 Node 版本 `^20.19.0 || >=22.12.0`,确保与依赖兼容。
|
||||||
|
|
||||||
|
## 10. 扩展与约束原则
|
||||||
|
- 遵循 `CLAUDE.md` 中的严格开发准则:先确认需求,再最小化实现,禁止未授权的额外功能或样式更改。
|
||||||
|
- Store 只负责状态管理,API 调用留在组件或服务层,避免职责交叉。
|
||||||
|
- 与后台的交互需要通过 `operationContext` 提供统一的通知描述,保持日志与提示文案一致。
|
||||||
|
- 新增页面需按“配置 → 组件 → 仪表板页注册”的流程接入,保证页面切换逻辑集中管理。
|
||||||
66
package-lock.json
generated
66
package-lock.json
generated
@ -9,6 +9,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"element-plus": "^2.11.2",
|
"element-plus": "^2.11.2",
|
||||||
|
"online-3d-viewer": "^0.16.0",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"vue": "^3.5.18",
|
"vue": "^3.5.18",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.5.1"
|
||||||
@ -59,6 +60,7 @@
|
|||||||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.3",
|
"@babel/generator": "^7.28.3",
|
||||||
@ -1592,6 +1594,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@simonwep/pickr": {
|
||||||
|
"version": "1.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.9.0.tgz",
|
||||||
|
"integrity": "sha512-oEYvv15PyfZzjoAzvXYt3UyNGwzsrpFxLaZKzkOSd0WYBVwLd19iJerePDONxC1iF6+DpcswPdLIM2KzCJuYFg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"core-js": "3.32.2",
|
||||||
|
"nanopop": "2.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@sindresorhus/merge-streams": {
|
"node_modules/@sindresorhus/merge-streams": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
|
||||||
@ -1630,6 +1642,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
||||||
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash": "*"
|
"@types/lodash": "*"
|
||||||
}
|
}
|
||||||
@ -2022,6 +2035,7 @@
|
|||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@ -2159,6 +2173,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.8.2",
|
"baseline-browser-mapping": "^2.8.2",
|
||||||
"caniuse-lite": "^1.0.30001741",
|
"caniuse-lite": "^1.0.30001741",
|
||||||
@ -2286,6 +2301,17 @@
|
|||||||
"url": "https://github.com/sponsors/mesqueeb"
|
"url": "https://github.com/sponsors/mesqueeb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/core-js": {
|
||||||
|
"version": "3.32.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.2.tgz",
|
||||||
|
"integrity": "sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/core-js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
@ -2526,6 +2552,7 @@
|
|||||||
"integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==",
|
"integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@ -2587,6 +2614,7 @@
|
|||||||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"eslint-config-prettier": "bin/cli.js"
|
"eslint-config-prettier": "bin/cli.js"
|
||||||
},
|
},
|
||||||
@ -2829,6 +2857,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fflate": {
|
||||||
|
"version": "0.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||||
|
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/figures": {
|
"node_modules/figures": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
|
||||||
@ -3277,13 +3311,15 @@
|
|||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/lodash-es": {
|
"node_modules/lodash-es": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/lodash-unified": {
|
"node_modules/lodash-unified": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
@ -3382,6 +3418,12 @@
|
|||||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nanopop": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-fzN+T2K7/Ah25XU02MJkPZ5q4Tj5FpjmIYq4rvoHX4yb16HzFdCO6JxFFn5Y/oBhQ8no8fUZavnyIv9/+xkBBw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/natural-compare": {
|
"node_modules/natural-compare": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||||
@ -3452,6 +3494,17 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/online-3d-viewer": {
|
||||||
|
"version": "0.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/online-3d-viewer/-/online-3d-viewer-0.16.0.tgz",
|
||||||
|
"integrity": "sha512-Mcmo41TM3K+svlMDRH8ySKSY2e8s7Sssdb5U9LV3gkFKVWGGuS304Vk5gqxopAJbE72DpsC67Ve3YNtcAuROwQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@simonwep/pickr": "1.9.0",
|
||||||
|
"fflate": "0.8.2",
|
||||||
|
"three": "0.176.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/open": {
|
"node_modules/open": {
|
||||||
"version": "10.2.0",
|
"version": "10.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz",
|
||||||
@ -3678,6 +3731,7 @@
|
|||||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
@ -3946,6 +4000,12 @@
|
|||||||
"url": "https://opencollective.com/synckit"
|
"url": "https://opencollective.com/synckit"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/three": {
|
||||||
|
"version": "0.176.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/three/-/three-0.176.0.tgz",
|
||||||
|
"integrity": "sha512-PWRKYWQo23ojf9oZSlRGH8K09q7nRSWx6LY/HF/UUrMdYgN9i1e2OwJYHoQjwc6HF/4lvvYLC5YC1X8UJL2ZpA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.15",
|
"version": "0.2.15",
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||||
@ -4070,6 +4130,7 @@
|
|||||||
"integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==",
|
"integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
@ -4289,6 +4350,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz",
|
||||||
"integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
|
"integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.5.21",
|
"@vue/compiler-dom": "3.5.21",
|
||||||
"@vue/compiler-sfc": "3.5.21",
|
"@vue/compiler-sfc": "3.5.21",
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"element-plus": "^2.11.2",
|
"element-plus": "^2.11.2",
|
||||||
|
"online-3d-viewer": "^0.16.0",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"vue": "^3.5.18",
|
"vue": "^3.5.18",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.5.1"
|
||||||
|
|||||||
@ -46,6 +46,7 @@
|
|||||||
--color-bg-secondary: rgb(var(--color-bg-secondary-base));
|
--color-bg-secondary: rgb(var(--color-bg-secondary-base));
|
||||||
--color-bg-tertiary: rgb(var(--color-bg-tertiary-base));
|
--color-bg-tertiary: rgb(var(--color-bg-tertiary-base));
|
||||||
--color-bg-quaternary: rgb(37, 37, 37);
|
--color-bg-quaternary: rgb(37, 37, 37);
|
||||||
|
--color-bg-viewer-light: rgb(220, 222, 225); /* 3D查看器浅色背景 */
|
||||||
--color-bg-card: rgba(var(--color-bg-secondary-base), 0.8);
|
--color-bg-card: rgba(var(--color-bg-secondary-base), 0.8);
|
||||||
--color-bg-hover: rgba(var(--color-white-base), 0.05);
|
--color-bg-hover: rgba(var(--color-white-base), 0.05);
|
||||||
--color-bg-active: rgba(var(--color-primary-base), 0.1);
|
--color-bg-active: rgba(var(--color-primary-base), 0.1);
|
||||||
|
|||||||
@ -214,6 +214,13 @@ import { creoApi } from '@/services/creoApi.js'
|
|||||||
// Emits
|
// Emits
|
||||||
const emit = defineEmits(['close', 'start-optimization'])
|
const emit = defineEmits(['close', 'start-optimization'])
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
subassemblyPath: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
const sections = ref({
|
const sections = ref({
|
||||||
basic: { expanded: true },
|
basic: { expanded: true },
|
||||||
@ -229,7 +236,7 @@ const configDefaults = getGeometryOptimizationDefaults()
|
|||||||
// 当前参数
|
// 当前参数
|
||||||
const parameters = ref({
|
const parameters = ref({
|
||||||
software_type: configDefaults.SOFTWARE_TYPE,
|
software_type: configDefaults.SOFTWARE_TYPE,
|
||||||
project_name: window.appState?.currentProject?.name || 'Unknown Project',
|
project_name: props.subassemblyPath || window.appState?.currentProject?.name || 'Unknown Project',
|
||||||
method: configDefaults.METHOD,
|
method: configDefaults.METHOD,
|
||||||
quality: configDefaults.QUALITY,
|
quality: configDefaults.QUALITY,
|
||||||
chord_height: configDefaults.CHORD_HEIGHT,
|
chord_height: configDefaults.CHORD_HEIGHT,
|
||||||
@ -273,6 +280,12 @@ const startOptimization = async () => {
|
|||||||
assign_mass_properties: parameters.value.assign_mass_properties
|
assign_mass_properties: parameters.value.assign_mass_properties
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果项目名称不是'Unknown Project',则认为是子装配体路径,添加参数
|
||||||
|
if (parameters.value.project_name !== 'Unknown Project') {
|
||||||
|
// 增加一个参数,参数值为项目名称的值 (即传过来的路径)
|
||||||
|
apiParams.component_path = parameters.value.project_name
|
||||||
|
}
|
||||||
|
|
||||||
// 调用API
|
// 调用API
|
||||||
const result = await creoApi.startShrinkwrapShell(apiParams)
|
const result = await creoApi.startShrinkwrapShell(apiParams)
|
||||||
|
|
||||||
|
|||||||
@ -175,6 +175,15 @@
|
|||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
<span>删除选中组件 ({{ selectedComponents.size }})</span>
|
<span>删除选中组件 ({{ selectedComponents.size }})</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="hasSubassemblySelected"
|
||||||
|
class="action-btn"
|
||||||
|
style="background: var(--color-warning); color: var(--color-text-primary); border-color: transparent;"
|
||||||
|
@click="openGeometricOptimization"
|
||||||
|
>
|
||||||
|
<i class="fas fa-magic"></i>
|
||||||
|
<span>对选中模型进行几何优化</span>
|
||||||
|
</button>
|
||||||
<button class="continue-btn primary" @click="continueToDeleteConfig">
|
<button class="continue-btn primary" @click="continueToDeleteConfig">
|
||||||
<i class="fas fa-arrow-right"></i>
|
<i class="fas fa-arrow-right"></i>
|
||||||
<span>继续层级删除配置</span>
|
<span>继续层级删除配置</span>
|
||||||
@ -198,7 +207,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['show-hierarchy-deletion-params'])
|
const emit = defineEmits(['show-hierarchy-deletion-params', 'show-geometry-optimization-params'])
|
||||||
|
|
||||||
const currentView = ref('tree')
|
const currentView = ref('tree')
|
||||||
const selectedComponents = ref(new Set())
|
const selectedComponents = ref(new Set())
|
||||||
@ -344,6 +353,32 @@ const toggleSelection = (componentPath) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否选中了子装配体
|
||||||
|
const hasSubassemblySelected = computed(() => {
|
||||||
|
return Array.from(selectedComponents.value).some(path => {
|
||||||
|
const component = hierarchyData.value.find(c => c.path === path)
|
||||||
|
if (!component) return false
|
||||||
|
// 检查类型是否为装配体 (ASM) 或文件名以 .asm 结尾
|
||||||
|
return (component.type && (component.type.toUpperCase() === 'ASM' || component.type.toUpperCase() === 'ASSEMBLY')) ||
|
||||||
|
(component.filename && component.filename.toLowerCase().endsWith('.asm'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const openGeometricOptimization = () => {
|
||||||
|
// 获取选中的子装配体路径
|
||||||
|
const selectedSubassemblies = Array.from(selectedComponents.value).filter(path => {
|
||||||
|
const component = hierarchyData.value.find(c => c.path === path)
|
||||||
|
if (!component) return false
|
||||||
|
return (component.type && (component.type.toUpperCase() === 'ASM' || component.type.toUpperCase() === 'ASSEMBLY')) ||
|
||||||
|
(component.filename && component.filename.toLowerCase().endsWith('.asm'))
|
||||||
|
})
|
||||||
|
|
||||||
|
if (selectedSubassemblies.length > 0) {
|
||||||
|
// 优先使用第一个选中的子装配体
|
||||||
|
emit('show-geometry-optimization-params', { subassemblyPath: selectedSubassemblies[0] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const exportResults = () => {
|
const exportResults = () => {
|
||||||
const data = {
|
const data = {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export default {
|
|||||||
<span>模型结构树</span>
|
<span>模型结构树</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tree-container">
|
<div class="tree-container">
|
||||||
<ModelTreeNode :node="modelTree" />
|
<ModelTreeNode :node="modelTree" :selected-mesh-id="selectedMeshId" @mesh-click="handleTreeNodeClick" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -96,6 +96,7 @@ const isLoading = ref(false)
|
|||||||
const modelInfo = ref(null)
|
const modelInfo = ref(null)
|
||||||
const modelTree = ref(null) // 模型树数据
|
const modelTree = ref(null) // 模型树数据
|
||||||
const isDragging = ref(false) // 拖拽状态
|
const isDragging = ref(false) // 拖拽状态
|
||||||
|
const selectedMeshId = ref(null) // 当前选中的mesh实例ID({nodeId, meshIndex})
|
||||||
|
|
||||||
// 初始化查看器
|
// 初始化查看器
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -106,6 +107,12 @@ onMounted(() => {
|
|||||||
edgeSettings: new OV.EdgeSettings(false, new OV.RGBColor(80, 80, 80), 1),
|
edgeSettings: new OV.EdgeSettings(false, new OV.RGBColor(80, 80, 80), 1),
|
||||||
onModelLoaded: handleModelLoaded
|
onModelLoaded: handleModelLoaded
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 设置鼠标点击处理器
|
||||||
|
if (viewer) {
|
||||||
|
const internalViewer = viewer.GetViewer()
|
||||||
|
internalViewer.SetMouseClickHandler(handleMeshClick)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -219,6 +226,7 @@ const buildModelTree = (model) => {
|
|||||||
type: 'mesh',
|
type: 'mesh',
|
||||||
depth: depth + 1,
|
depth: depth + 1,
|
||||||
meshIndex: meshIndex,
|
meshIndex: meshIndex,
|
||||||
|
nodeId: node.GetId(), // 保存节点ID用于匹配
|
||||||
vertexCount: mesh.VertexCount(),
|
vertexCount: mesh.VertexCount(),
|
||||||
triangleCount: mesh.TriangleCount()
|
triangleCount: mesh.TriangleCount()
|
||||||
})
|
})
|
||||||
@ -270,6 +278,60 @@ const handleModelLoaded = () => {
|
|||||||
console.error('获取模型统计信息失败:', error)
|
console.error('获取模型统计信息失败:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理3D模型点击事件
|
||||||
|
const handleMeshClick = (button, mouseCoords) => {
|
||||||
|
if (button !== 1) return // 只处理左键点击
|
||||||
|
|
||||||
|
try {
|
||||||
|
const internalViewer = viewer.GetViewer()
|
||||||
|
const meshUserData = internalViewer.GetMeshUserDataUnderMouse(OV.IntersectionMode.MeshOnly, mouseCoords)
|
||||||
|
|
||||||
|
if (meshUserData) {
|
||||||
|
// 获取mesh实例ID
|
||||||
|
const meshInstanceId = meshUserData.originalMeshInstance.id
|
||||||
|
const meshId = {
|
||||||
|
nodeId: meshInstanceId.nodeId,
|
||||||
|
meshIndex: meshInstanceId.meshIndex
|
||||||
|
}
|
||||||
|
console.log('点击3D模型,获取到的ID:', meshId)
|
||||||
|
selectedMeshId.value = meshId
|
||||||
|
} else {
|
||||||
|
// 点击空白处,取消选中
|
||||||
|
selectedMeshId.value = null
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('处理mesh点击失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理模型树节点点击事件
|
||||||
|
const handleTreeNodeClick = (meshId) => {
|
||||||
|
selectedMeshId.value = meshId
|
||||||
|
focusOnMesh(meshId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 聚焦到指定mesh
|
||||||
|
const focusOnMesh = (meshId) => {
|
||||||
|
if (!viewer || !meshId) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const internalViewer = viewer.GetViewer()
|
||||||
|
|
||||||
|
// 获取mesh的包围球
|
||||||
|
const boundingSphere = internalViewer.GetBoundingSphere((meshUserData) => {
|
||||||
|
const id = meshUserData.originalMeshInstance.id
|
||||||
|
return id.nodeId === meshId.nodeId && id.meshIndex === meshId.meshIndex
|
||||||
|
})
|
||||||
|
|
||||||
|
if (boundingSphere) {
|
||||||
|
// 聚焦相机到该mesh
|
||||||
|
internalViewer.FitSphereToWindow(boundingSphere, true)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('聚焦到mesh失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tree-node">
|
<div class="tree-node" ref="nodeRef">
|
||||||
<div
|
<div
|
||||||
class="node-label"
|
class="node-label"
|
||||||
:class="{ 'has-children': hasChildren }"
|
:class="{
|
||||||
|
'has-children': hasChildren,
|
||||||
|
'mesh-node': node.type === 'mesh',
|
||||||
|
'selected': isSelected
|
||||||
|
}"
|
||||||
@click="toggleExpand"
|
@click="toggleExpand"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
@ -21,39 +25,113 @@
|
|||||||
v-for="(child, index) in node.children"
|
v-for="(child, index) in node.children"
|
||||||
:key="index"
|
:key="index"
|
||||||
:node="child"
|
:node="child"
|
||||||
|
:selected-mesh-id="selectedMeshId"
|
||||||
|
@mesh-click="(meshId) => emit('mesh-click', meshId)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed, watch, nextTick } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
node: {
|
node: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
selectedMeshId: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['mesh-click'])
|
||||||
|
|
||||||
const expanded = ref(props.node.expanded || false)
|
const expanded = ref(props.node.expanded || false)
|
||||||
|
const nodeRef = ref(null)
|
||||||
|
|
||||||
const hasChildren = computed(() => {
|
const hasChildren = computed(() => {
|
||||||
return props.node.children && props.node.children.length > 0
|
return props.node.children && props.node.children.length > 0
|
||||||
})
|
})
|
||||||
|
|
||||||
const toggleExpand = () => {
|
const toggleExpand = () => {
|
||||||
|
// 如果是mesh节点,触发点击事件
|
||||||
|
if (props.node.type === 'mesh') {
|
||||||
|
const meshId = {
|
||||||
|
nodeId: props.node.nodeId,
|
||||||
|
meshIndex: props.node.meshIndex
|
||||||
|
}
|
||||||
|
emit('mesh-click', meshId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则切换展开状态
|
||||||
if (hasChildren.value) {
|
if (hasChildren.value) {
|
||||||
expanded.value = !expanded.value
|
expanded.value = !expanded.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断当前mesh节点是否被选中
|
||||||
|
const isSelected = computed(() => {
|
||||||
|
if (props.node.type !== 'mesh' || !props.selectedMeshId) return false
|
||||||
|
const result = props.node.nodeId === props.selectedMeshId.nodeId &&
|
||||||
|
props.node.meshIndex === props.selectedMeshId.meshIndex
|
||||||
|
if (result) {
|
||||||
|
console.log('节点匹配成功:', {
|
||||||
|
nodeName: props.node.name,
|
||||||
|
nodeId: props.node.nodeId,
|
||||||
|
meshIndex: props.node.meshIndex,
|
||||||
|
selectedNodeId: props.selectedMeshId.nodeId,
|
||||||
|
selectedMeshIndex: props.selectedMeshId.meshIndex
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
const getIcon = () => {
|
const getIcon = () => {
|
||||||
if (props.node.type === 'mesh') {
|
if (props.node.type === 'mesh') {
|
||||||
return 'fa-cube'
|
return 'fa-cube'
|
||||||
}
|
}
|
||||||
return expanded.value ? 'fa-folder-open' : 'fa-folder'
|
return expanded.value ? 'fa-folder-open' : 'fa-folder'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查子节点中是否有被选中的mesh
|
||||||
|
const hasSelectedChild = () => {
|
||||||
|
if (!props.node.children || !props.selectedMeshId) return false
|
||||||
|
|
||||||
|
const checkNode = (node) => {
|
||||||
|
if (node.type === 'mesh') {
|
||||||
|
return node.nodeId === props.selectedMeshId.nodeId &&
|
||||||
|
node.meshIndex === props.selectedMeshId.meshIndex
|
||||||
|
}
|
||||||
|
if (node.children) {
|
||||||
|
return node.children.some(checkNode)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return props.node.children.some(checkNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听选中状态变化,自动展开到选中节点
|
||||||
|
watch(() => props.selectedMeshId, () => {
|
||||||
|
if (hasSelectedChild()) {
|
||||||
|
expanded.value = true
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
// 当节点被选中时,滚动到可视区域
|
||||||
|
watch(isSelected, async (newVal) => {
|
||||||
|
if (newVal && nodeRef.value) {
|
||||||
|
await nextTick()
|
||||||
|
nodeRef.value.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'nearest',
|
||||||
|
inline: 'nearest'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -81,6 +159,39 @@ const getIcon = () => {
|
|||||||
font-weight: var(--font-weight-medium);
|
font-weight: var(--font-weight-medium);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.node-label.mesh-node {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-label.mesh-node:hover {
|
||||||
|
background: var(--color-white-rgb-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-label.selected {
|
||||||
|
background: var(--color-primary-rgb-2);
|
||||||
|
border-left: 4px solid var(--color-primary);
|
||||||
|
padding-left: 4px;
|
||||||
|
font-weight: var(--font-weight-semibold);
|
||||||
|
color: var(--color-primary);
|
||||||
|
box-shadow: 0 2px 8px var(--color-primary-rgb-2);
|
||||||
|
animation: highlight 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes highlight {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateX(2px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.expand-icon {
|
.expand-icon {
|
||||||
width: 12px;
|
width: 12px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
|||||||
@ -91,7 +91,8 @@ const CAD_SOFTWARE_DEFINITIONS = {
|
|||||||
optimization: '/api/creo/shrinkwrap/shell',
|
optimization: '/api/creo/shrinkwrap/shell',
|
||||||
deleteComponent: '/api/creo/component/delete-by-path',
|
deleteComponent: '/api/creo/component/delete-by-path',
|
||||||
componentChildren: '/api/creo/component/children',
|
componentChildren: '/api/creo/component/children',
|
||||||
export: '/api/export/model'
|
export: '/api/export/model',
|
||||||
|
subassemblyHierarchyDelete: '/api/creo/subassembly/hierarchy/delete'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
REVIT: {
|
REVIT: {
|
||||||
|
|||||||
@ -87,6 +87,7 @@ const shellAnalysisData = ref(null)
|
|||||||
const hierarchyAnalysisData = ref(null)
|
const hierarchyAnalysisData = ref(null)
|
||||||
const geometryComplexityData = ref(null)
|
const geometryComplexityData = ref(null)
|
||||||
const geometryOptimizationResultData = ref(null)
|
const geometryOptimizationResultData = ref(null)
|
||||||
|
const geometryOptimizationSelectedSubassembly = ref(null)
|
||||||
|
|
||||||
// 信息面板控制
|
// 信息面板控制
|
||||||
const showInfoPanel = ref(false)
|
const showInfoPanel = ref(false)
|
||||||
@ -139,6 +140,8 @@ const currentComponentProps = computed(() => {
|
|||||||
props.analysisData = geometryComplexityData.value
|
props.analysisData = geometryComplexityData.value
|
||||||
} else if (currentPage.value === PAGE_TYPES.GEOMETRY_OPTIMIZATION_RESULT) {
|
} else if (currentPage.value === PAGE_TYPES.GEOMETRY_OPTIMIZATION_RESULT) {
|
||||||
props.resultData = geometryOptimizationResultData.value
|
props.resultData = geometryOptimizationResultData.value
|
||||||
|
} else if (currentPage.value === PAGE_TYPES.GEOMETRY_OPTIMIZATION_PARAMS) {
|
||||||
|
props.subassemblyPath = geometryOptimizationSelectedSubassembly.value
|
||||||
}
|
}
|
||||||
|
|
||||||
return props
|
return props
|
||||||
@ -175,7 +178,12 @@ const handleShowGeometryComplexityResult = (data) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理跳转到几何优化分析参数设置页面
|
// 处理跳转到几何优化分析参数设置页面
|
||||||
const handleShowGeometryOptimizationParams = () => {
|
const handleShowGeometryOptimizationParams = (payload) => {
|
||||||
|
if (payload && payload.subassemblyPath) {
|
||||||
|
geometryOptimizationSelectedSubassembly.value = payload.subassemblyPath
|
||||||
|
} else {
|
||||||
|
geometryOptimizationSelectedSubassembly.value = null
|
||||||
|
}
|
||||||
currentPage.value = PAGE_TYPES.GEOMETRY_OPTIMIZATION_PARAMS
|
currentPage.value = PAGE_TYPES.GEOMETRY_OPTIMIZATION_PARAMS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user