From 1c75aa621a969e8474f22487dcfa8c1034d1e386 Mon Sep 17 00:00:00 2001 From: alivender <13898766233@163.com> Date: Tue, 29 Apr 2025 11:05:30 +0800 Subject: [PATCH] feat: Enhance equipment components with pin functionality and constraint management - Added pin support to MechanicalButton, enabling pin-click events and componentId handling. - Updated Pin component to manage constraint states and colors dynamically. - Integrated SMT_LED with pin functionality, allowing LED state to respond to constraints. - Enhanced Wire component to reflect constraint colors and manage wire states based on pin connections. - Introduced wireManager for managing wire states and constraints. - Implemented a constraints store for managing and notifying constraint state changes across components. - Updated component configuration to remove appearance options and clarify constraint descriptions. - Improved ProjectView to handle optional chaining for props and ensure robust data handling. - Initialized constraint communication in main application entry point. --- src/APIClient.ts | 58 ++++- src/components/DiagramCanvas.css | 80 ------ src/components/DiagramCanvas.vue | 236 ++++++++---------- .../equipments/MechanicalButton.vue | 42 +++- src/components/equipments/Pin.vue | 187 +++++++------- src/components/equipments/SMT_LED.vue | 153 ++++++------ src/components/equipments/Wire.vue | 53 +++- src/components/equipments/componentConfig.ts | 18 +- src/components/wireManager.ts | 86 +++++++ src/main.ts | 4 + src/stores/constraints.ts | 82 ++++++ src/views/ProjectView.vue | 11 +- 12 files changed, 590 insertions(+), 420 deletions(-) delete mode 100644 src/components/DiagramCanvas.css create mode 100644 src/components/wireManager.ts create mode 100644 src/stores/constraints.ts diff --git a/src/APIClient.ts b/src/APIClient.ts index c823f76..0b01edd 100644 --- a/src/APIClient.ts +++ b/src/APIClient.ts @@ -8,6 +8,9 @@ /* eslint-disable */ // ReSharper disable InconsistentNaming +import { batchSetConstraintStates, notifyConstraintChange } from './stores/constraints'; +import type { ConstraintLevel } from './stores/constraints'; + export class Client { private http: { fetch(url: RequestInfo, init?: RequestInit): Promise }; private baseUrl: string; @@ -866,4 +869,57 @@ function throwException(message: string, status: number, response: string, heade throw result; else throw new ApiException(message, status, response, headers, null); -} \ No newline at end of file +} + +// 约束通信相关方法 +export function receiveConstraintUpdates(constraints: Record) { + // 批量更新约束状态 + batchSetConstraintStates(constraints); +} + +export function sendConstraintUpdate(constraint: string, level: ConstraintLevel) { + // 向后端发送约束状态变化 + console.log(`发送约束 ${constraint} 状态变化为 ${level}`); + + // TODO: 实际的WebSocket或HTTP请求发送约束变化 + // 例如: + // socket.emit('constraintUpdate', { constraint, level }); + // 或 + // fetch('/api/constraints', { + // method: 'POST', + // body: JSON.stringify({ constraint, level }), + // headers: { 'Content-Type': 'application/json' } + // }); +} + +// 初始化约束通信 +export function initConstraintCommunication() { + // 监听服务器发来的约束状态变化 + // 示例: + // socket.on('constraintUpdates', (data) => { + // receiveConstraintUpdates(data); + // }); + + // 模拟接收一些初始约束状态 + setTimeout(() => { + receiveConstraintUpdates({ + 'A1': 'high', + 'A2': 'low', + 'A3': 'undefined' + }); + }, 1000); +} + +// 覆盖全局notifyConstraintChange,加入发送逻辑 +const originalNotifyConstraintChange = notifyConstraintChange; +const wrappedNotifyConstraintChange = (constraint: string, level: ConstraintLevel) => { + // 调用原始方法更新本地状态 + originalNotifyConstraintChange(constraint, level); + + // 向后端发送更新 + sendConstraintUpdate(constraint, level); +}; + +// 替换全局方法 +(window as any).__notifyConstraintChange = notifyConstraintChange; +(window as any).notifyConstraintChange = wrappedNotifyConstraintChange; \ No newline at end of file diff --git a/src/components/DiagramCanvas.css b/src/components/DiagramCanvas.css deleted file mode 100644 index 49d9def..0000000 --- a/src/components/DiagramCanvas.css +++ /dev/null @@ -1,80 +0,0 @@ -.diagram-canvas { - position: relative; - width: 4000px; - height: 4000px; - transform-origin: 0 0; -} - -/* 将网格线应用到容器而不是画布上,确保覆盖整个可视区域 */ -.flex-1.min-w-\[60\%\].bg-base-200.relative.overflow-auto { - background-image: - linear-gradient(to right, rgba(100, 100, 100, 0.1) 1px, transparent 1px), - linear-gradient(to bottom, rgba(100, 100, 100, 0.1) 1px, transparent 1px), - linear-gradient(to right, rgba(80, 80, 80, 0.2) 100px, transparent 100px), - linear-gradient(to bottom, rgba(80, 80, 80, 0.2) 100px, transparent 100px); - background-size: 20px 20px, 20px 20px, 100px 100px, 100px 100px; - background-position: 0 0; -} - -/* 为黑暗模式设置不同的网格线颜色 */ -:root[data-theme="dark"] .flex-1.min-w-\[60\%\].bg-base-200.relative.overflow-auto { - background-image: - linear-gradient(to right, rgba(200, 200, 200, 0.1) 1px, transparent 1px), - linear-gradient(to bottom, rgba(200, 200, 200, 0.1) 1px, transparent 1px), - linear-gradient(to right, rgba(180, 180, 180, 0.15) 100px, transparent 100px), - linear-gradient(to bottom, rgba(180, 180, 180, 0.15) 100px, transparent 100px); - background-size: 20px 20px, 20px 20px, 100px 100px, 100px 100px; - background-position: 0 0; -} - -/* 禁用滚动条 */ -.flex-1.min-w-\[60\%\].bg-base-200.relative.overflow-auto::-webkit-scrollbar { - display: none; /* Chrome, Safari, Opera */ -} - -.flex-1.min-w-\[60\%\].bg-base-200.relative.overflow-auto { - -ms-overflow-style: none; /* IE and Edge */ - scrollbar-width: none; /* Firefox */ -} - -/* 元器件容器样式 */ -.component-wrapper { - position: relative; - padding: 5px; - box-sizing: border-box; - display: inline-block; /* 确保元素宽度基于内容 */ - max-width: fit-content; /* 强制宽度适应内容 */ - max-height: fit-content; /* 强制高度适应内容 */ - overflow: visible; /* 允许内容溢出(用于显示边框) */ -} - -/* 悬停状态 */ -.component-hover::before { - content: ''; - position: absolute; - top: -4px; - left: -4px; - right: -4px; - bottom: -4px; - border: 3px dashed #3498db; - pointer-events: none; - z-index: 1; - border-radius: 4px; - box-sizing: content-box; -} - -/* 选中状态 */ -.component-selected::before { - content: ''; - position: absolute; - top: -4px; - left: -4px; - right: -4px; - bottom: -4px; - border: 4px dashed #e74c3c; - border-color: #e74c3c #f39c12 #3498db #2ecc71; - pointer-events: none; - z-index: 1; - border-radius: 4px; - box-sizing: content-box; -} diff --git a/src/components/DiagramCanvas.vue b/src/components/DiagramCanvas.vue index 1abc48f..60b0796 100644 --- a/src/components/DiagramCanvas.vue +++ b/src/components/DiagramCanvas.vue @@ -19,13 +19,10 @@ :end-y="wire.endY" :stroke-color="wire.color || '#4a5568'" :stroke-width="2" - :is-active="wireSelectedId === wire.id" + :is-active="false" :start-component-id="wire.startComponentId" - :start-pin-label="wire.startPinLabel" :end-component-id="wire.endComponentId" - :end-pin-label="wire.endPinLabel" :constraint="wire.constraint" - @click="handleWireClick(wire)" /> @@ -82,6 +79,15 @@ diff --git a/src/components/equipments/Pin.vue b/src/components/equipments/Pin.vue index 53ba3fd..0ecc89b 100644 --- a/src/components/equipments/Pin.vue +++ b/src/components/equipments/Pin.vue @@ -1,71 +1,35 @@ diff --git a/src/components/equipments/SMT_LED.vue b/src/components/equipments/SMT_LED.vue index fbd2cc7..6619599 100644 --- a/src/components/equipments/SMT_LED.vue +++ b/src/components/equipments/SMT_LED.vue @@ -14,16 +14,15 @@ - @@ -35,46 +34,64 @@ x="12" y="12" :fill="ledColor" - :style="{ opacity: brightness/100 * 0.3 }" + :style="{ opacity: 0.3 }" rx="18" ry="18" filter="blur(5px)" class="glow" /> + +
+ +
diff --git a/src/components/equipments/Wire.vue b/src/components/equipments/Wire.vue index d52e2f7..86218cb 100644 --- a/src/components/equipments/Wire.vue +++ b/src/components/equipments/Wire.vue @@ -21,7 +21,8 @@