Commit e3663aab authored by fenghen777's avatar fenghen777

feat: Implement core diagram editor functionality including a component...

feat: Implement core diagram editor functionality including a component library, React Flow state management, and property editing.
parent 5ef2e19f
...@@ -383,8 +383,7 @@ ...@@ -383,8 +383,7 @@
background: #1a1a28; background: #1a1a28;
} }
.portTypeSelect, .portTypeSelect {
.portSideSelect {
width: 52px; width: 52px;
padding: 3px 2px; padding: 3px 2px;
border: 1px solid #2a2a3a; border: 1px solid #2a2a3a;
...@@ -395,8 +394,26 @@ ...@@ -395,8 +394,26 @@
cursor: pointer; cursor: pointer;
} }
.portSideSelect { .portConnectorInput {
width: 48px; width: 60px;
padding: 3px 5px;
border: 1px solid transparent;
border-radius: 3px;
background: transparent;
color: #6366f1;
font-size: 10px;
font-family: 'Consolas', monospace;
flex-shrink: 0;
}
.portConnectorInput:focus {
outline: none;
border-color: #6366f1;
background: #1a1a28;
}
.portConnectorInput::placeholder {
color: #444;
} }
.portDeleteBtn { .portDeleteBtn {
......
...@@ -6,12 +6,6 @@ import { PORT_TYPES } from '../../utils/constants'; ...@@ -6,12 +6,6 @@ import { PORT_TYPES } from '../../utils/constants';
import useComponentLibrary from '../../hooks/useComponentLibrary'; import useComponentLibrary from '../../hooks/useComponentLibrary';
import styles from './ComponentEditor.module.css'; import styles from './ComponentEditor.module.css';
const SIDES = [
{ value: 'top', label: '上' },
{ value: 'bottom', label: '下' },
{ value: 'left', label: '左' },
{ value: 'right', label: '右' },
];
export default function PortEditor() { export default function PortEditor() {
const { editingTemplate, updatePort, removePort, addPort } = useComponentLibrary(); const { editingTemplate, updatePort, removePort, addPort } = useComponentLibrary();
...@@ -76,6 +70,15 @@ export default function PortEditor() { ...@@ -76,6 +70,15 @@ export default function PortEditor() {
placeholder="端点描述" placeholder="端点描述"
/> />
{/* Connector 参数 */}
<input
className={styles.portConnectorInput}
value={port.connector || ''}
onChange={(e) => updatePort(port.id, { connector: e.target.value })}
placeholder="connector"
title="Modelica 端口标识"
/>
{/* 类型选择 */} {/* 类型选择 */}
<select <select
className={styles.portTypeSelect} className={styles.portTypeSelect}
...@@ -87,17 +90,6 @@ export default function PortEditor() { ...@@ -87,17 +90,6 @@ export default function PortEditor() {
))} ))}
</select> </select>
{/* 位置选择 */}
<select
className={styles.portSideSelect}
value={port.side}
onChange={(e) => updatePort(port.id, { side: e.target.value })}
>
{SIDES.map(s => (
<option key={s.value} value={s.value}>{s.label}</option>
))}
</select>
{/* 删除 */} {/* 删除 */}
<button <button
className={styles.portDeleteBtn} className={styles.portDeleteBtn}
......
...@@ -97,7 +97,7 @@ export default function PropertiesPanel() { ...@@ -97,7 +97,7 @@ export default function PropertiesPanel() {
<div className={styles.portList}> <div className={styles.portList}>
{(selectedNode.data?.ports || selectedNode.data?.templateData?.ports || []).map(p => ( {(selectedNode.data?.ports || selectedNode.data?.templateData?.ports || []).map(p => (
<span key={typeof p === 'string' ? p : p.id || p} className={styles.portTag}> <span key={typeof p === 'string' ? p : p.id || p} className={styles.portTag}>
{typeof p === 'string' ? p : (p.portId != null ? p.portId : p.name)} {typeof p === 'string' ? p : (p.connector || p.name)}
</span> </span>
))} ))}
</div> </div>
......
...@@ -68,12 +68,24 @@ export function createBlankTemplate() { ...@@ -68,12 +68,24 @@ export function createBlankTemplate() {
shapes: [], shapes: [],
params: [], params: [],
ports: [ ports: [
{ id: 'in1', portId: 1, name: '1', description: '端点描述', type: 'generic', side: 'left', position: 0.5 }, { id: 'in1', portId: 1, name: '1', description: '', type: 'generic', side: 'left', position: 0.5, connector: 'in1' },
{ id: 'out1', portId: 2, name: '2', description: '端点描述', type: 'generic', side: 'right', position: 0.5 }, { id: 'out1', portId: 2, name: '2', description: '', type: 'generic', side: 'right', position: 0.5, connector: 'out1' },
], ],
}; };
} }
/**
* 根据已有端口列表生成默认 connector 名称和端口编号
* connector 使用 p 前缀:p1, p2, p3...
* 返回 { connector, portNum } 以便同步生成名称 portN
*/
function generateDefaultPortInfo(existingPorts) {
let n = 1;
const usedConnectors = new Set(existingPorts.map(p => p.connector));
while (usedConnectors.has(`p${n}`)) n++;
return { connector: `p${n}`, portNum: n };
}
const useComponentLibrary = create((set, get) => ({ const useComponentLibrary = create((set, get) => ({
templates: loadFromStorage(), templates: loadFromStorage(),
customCategories: loadCategories(), customCategories: loadCategories(),
...@@ -161,14 +173,18 @@ const useComponentLibrary = create((set, get) => ({ ...@@ -161,14 +173,18 @@ const useComponentLibrary = create((set, get) => ({
if (!current) return; if (!current) return;
get().pushHistory(); get().pushHistory();
const maxPortId = current.ports.reduce((max, p) => Math.max(max, p.portId || 0), 0); const maxPortId = current.ports.reduce((max, p) => Math.max(max, p.portId || 0), 0);
const side = port.side || 'left';
const { connector: defaultConnector, portNum } = generateDefaultPortInfo(current.ports);
const connector = port.connector || defaultConnector;
const newPort = { const newPort = {
id: `port-${Date.now()}`, id: `port-${Date.now()}`,
portId: maxPortId + 1, portId: maxPortId + 1,
name: `${maxPortId + 1}`, name: port.name || `port${portNum}`,
description: '端点描述', description: '',
type: 'generic', type: 'generic',
side: 'left', side,
position: 0.5, position: 0.5,
connector,
...port, ...port,
}; };
set({ editingTemplate: { ...current, ports: [...current.ports, newPort] } }); set({ editingTemplate: { ...current, ports: [...current.ports, newPort] } });
......
...@@ -90,10 +90,11 @@ const useFlowStore = create((set, get) => ({ ...@@ -90,10 +90,11 @@ const useFlowStore = create((set, get) => ({
id: `${p.id}-${counter}`, // 确保端口 id 全局唯一 id: `${p.id}-${counter}`, // 确保端口 id 全局唯一
portId: p.id, portId: p.id,
description: '', description: '',
connector: p.connector || p.name,
})) }))
: [ : [
{ id: `p-in-1-${counter}`, name: '输入1', portId: 1, description: '', type: 'generic', side: 'left', position: 0.5 }, { id: `p-in-1-${counter}`, name: '输入1', portId: 1, description: '', type: 'generic', side: 'left', position: 0.5, connector: 'in1' },
{ id: `p-out-1-${counter}`, name: '输出1', portId: 2, description: '', type: 'generic', side: 'right', position: 0.5 }, { id: `p-out-1-${counter}`, name: '输出1', portId: 2, description: '', type: 'generic', side: 'right', position: 0.5, connector: 'out1' },
]; ];
const templateData = { const templateData = {
......
This diff is collapsed.
...@@ -152,6 +152,8 @@ export function resolvePortName(handleId, type, ports) { ...@@ -152,6 +152,8 @@ export function resolvePortName(handleId, type, ports) {
if (ports && ports.length > 0) { if (ports && ports.length > 0) {
const port = ports.find(p => p.id === handleId); const port = ports.find(p => p.id === handleId);
if (port) { if (port) {
// 优先使用 connector 字段
if (port.connector) return port.connector;
const originalId = port.portId || port.id; const originalId = port.portId || port.id;
// 查映射表 // 查映射表
if (mapping && mapping.portMap[originalId]) { if (mapping && mapping.portMap[originalId]) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment