diff --git a/nl-vue/.cursor/worktrees.json b/nl-vue/.cursor/worktrees.json new file mode 100644 index 0000000..77e9744 --- /dev/null +++ b/nl-vue/.cursor/worktrees.json @@ -0,0 +1,5 @@ +{ + "setup-worktree": [ + "npm install" + ] +} diff --git a/nl-vue/src/views/nl_agv/layout/components/DeviceMarker.vue b/nl-vue/src/views/nl_agv/layout/components/DeviceMarker.vue deleted file mode 100644 index e69de29..0000000 diff --git a/nl-vue/src/views/nl_agv/layout/components/PropertyModal.vue b/nl-vue/src/views/nl_agv/layout/components/PropertyModal.vue deleted file mode 100644 index 9db7022..0000000 --- a/nl-vue/src/views/nl_agv/layout/components/PropertyModal.vue +++ /dev/null @@ -1,124 +0,0 @@ - - - - - diff --git a/nl-vue/src/views/nl_agv/layout/device-loader.js b/nl-vue/src/views/nl_agv/layout/device-loader.js index a54b035..d75895e 100644 --- a/nl-vue/src/views/nl_agv/layout/device-loader.js +++ b/nl-vue/src/views/nl_agv/layout/device-loader.js @@ -69,7 +69,7 @@ function isImageUrl(str) { function renderDeviceIcon(device) { if (isImageUrl(device.icon)) { // 如果是图片URL,使用img标签 - return `${device.name}`; + return `${device.name}`; } else { // 如果是emoji或其他文本,直接显示 return device.icon || '📍'; @@ -100,11 +100,18 @@ function renderDeviceList() {
${ type}
${devices.map(device => ` -
-
${renderDeviceIcon(device)}
+
+ ${device.name} +
${device.name}
${device.type}
diff --git a/nl-vue/src/views/nl_agv/layout/index.vue b/nl-vue/src/views/nl_agv/layout/index.vue index e69de29..3846d0f 100644 --- a/nl-vue/src/views/nl_agv/layout/index.vue +++ b/nl-vue/src/views/nl_agv/layout/index.vue @@ -0,0 +1,1251 @@ + + + + + diff --git a/nl-vue/src/views/nl_agv/layout/styles/map-editor.less b/nl-vue/src/views/nl_agv/layout/styles/map-editor.less deleted file mode 100644 index d22fcd0..0000000 --- a/nl-vue/src/views/nl_agv/layout/styles/map-editor.less +++ /dev/null @@ -1,358 +0,0 @@ -// AGV地图编辑器样式 -.agv-map-editor { - height: 100vh; - display: flex; - flex-direction: column; - background: linear-gradient(135deg, #0a0e27 0%, #1a1f3a 50%, #0f1419 100%); - color: #e0e6ed; - overflow: hidden; -} - -/* 顶部工具栏 */ -.toolbar { - height: 70px; - background: rgba(15, 20, 35, 0.95); - backdrop-filter: blur(20px); - border-bottom: 2px solid rgba(0, 255, 200, 0.3); - display: flex; - justify-content: space-between; - align-items: center; - padding: 0 30px; - box-shadow: 0 4px 30px rgba(0, 255, 200, 0.1); - z-index: 1000; - flex-shrink: 0; -} - -.toolbar-title { - font-size: 26px; - font-weight: 700; - background: linear-gradient(135deg, #00ffc8 0%, #00d4ff 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - letter-spacing: 1px; - text-shadow: 0 0 30px rgba(0, 255, 200, 0.5); -} - -.toolbar-right { - display: flex; - gap: 15px; -} - -.btn { - padding: 12px 28px; - border: none; - border-radius: 8px; - font-size: 15px; - font-weight: 600; - cursor: pointer; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.btn-primary { - background: linear-gradient(135deg, #00ffc8 0%, #00d4ff 100%); - color: #0a0e27; - box-shadow: 0 4px 20px rgba(0, 255, 200, 0.4); - - &:hover { - transform: translateY(-2px); - box-shadow: 0 6px 30px rgba(0, 255, 200, 0.6); - } -} - -.btn-secondary { - background: rgba(255, 255, 255, 0.1); - color: #00ffc8; - border: 1px solid rgba(0, 255, 200, 0.3); - - &:hover { - background: rgba(0, 255, 200, 0.2); - border-color: rgba(0, 255, 200, 0.5); - } -} - -/* 主内容区 */ -.main-content { - display: flex; - flex: 1; - overflow: hidden; - position: relative; -} - -/* 左侧设备面板 */ -.device-panel { - width: 320px; - flex-shrink: 0; - background: rgba(20, 25, 45, 0.8); - backdrop-filter: blur(15px); - border-right: 1px solid rgba(0, 255, 200, 0.2); - overflow-y: auto; - box-shadow: 4px 0 20px rgba(0, 0, 0, 0.3); - z-index: 100; -} - -.panel-header { - padding: 25px 20px; - border-bottom: 1px solid rgba(0, 255, 200, 0.2); - background: rgba(0, 255, 200, 0.05); - - h3 { - font-size: 18px; - font-weight: 600; - color: #00ffc8; - text-transform: uppercase; - letter-spacing: 1px; - margin: 0; - } -} - -.device-list { - padding: 20px; -} - -.device-category { - margin-bottom: 30px; -} - -.category-title { - font-size: 14px; - font-weight: 600; - color: #00d4ff; - margin-bottom: 15px; - text-transform: uppercase; - letter-spacing: 1px; -} - -.device-item { - display: flex; - align-items: center; - padding: 15px; - margin-bottom: 12px; - background: rgba(0, 255, 200, 0.05); - border: 1px solid rgba(0, 255, 200, 0.2); - border-radius: 10px; - cursor: grab; - transition: all 0.3s; - - &:hover { - background: rgba(0, 255, 200, 0.1); - border-color: rgba(0, 255, 200, 0.4); - transform: translateX(5px); - box-shadow: 0 4px 15px rgba(0, 255, 200, 0.2); - } - - &:active { - cursor: grabbing; - } - - &.dragging { - opacity: 0.5; - } -} - -.device-icon { - width: 50px; - height: 50px; - display: flex; - align-items: center; - justify-content: center; - font-size: 28px; - margin-right: 15px; - border-radius: 8px; - background: rgba(0, 255, 200, 0.1); -} - -.device-info { - flex: 1; -} - -.device-name { - font-size: 15px; - font-weight: 600; - color: #e0e6ed; - margin-bottom: 4px; -} - -.device-desc { - font-size: 12px; - color: #8b95a5; -} - -/* 地图编辑区 */ -.map-editor { - flex: 1; - display: flex; - flex-direction: column; - position: relative; - overflow: hidden; -} - -/* 地图画布容器 */ -.map-canvas-wrapper { - flex: 1; - overflow: auto; - position: relative; - background: repeating-linear-gradient( - 0deg, - rgba(0, 255, 200, 0.03) 0px, - transparent 1px, - transparent 20px, - rgba(0, 255, 200, 0.03) 21px - ), - repeating-linear-gradient( - 90deg, - rgba(0, 255, 200, 0.03) 0px, - transparent 1px, - transparent 20px, - rgba(0, 255, 200, 0.03) 21px - ); -} - -.map-canvas { - min-width: 100%; - min-height: 100%; - position: relative; - display: inline-block; - transition: transform 0.3s; -} - -.placeholder { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - text-align: center; - z-index: 1; -} - -.placeholder-icon { - font-size: 80px; - margin-bottom: 20px; - opacity: 0.3; -} - -.placeholder-text { - font-size: 18px; - color: #8b95a5; -} - -.map-image { - display: block; - user-select: none; - pointer-events: none; - max-width: 100%; - height: auto; -} - -.origin-canvas { - position: absolute; - top: 0; - left: 0; - pointer-events: none; - z-index: 10; -} - -.devices-layer { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 20; - pointer-events: none; -} - -/* 右下角浮动控制面板 */ -.floating-controls { - position: fixed; - bottom: 30px; - right: 30px; - z-index: 200; - display: flex; - flex-direction: column; - gap: 15px; - align-items: flex-end; - pointer-events: none; - - > * { - pointer-events: auto; - } -} - -.origin-info { - padding: 12px 20px; - background: rgba(20, 25, 45, 0.95); - backdrop-filter: blur(15px); - border: 1px solid rgba(0, 255, 200, 0.3); - border-radius: 8px; - color: #00ffc8; - font-size: 14px; - font-weight: 600; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); -} - -.control-buttons { - display: flex; - gap: 10px; -} - -.control-btn { - width: 50px; - height: 50px; - background: rgba(20, 25, 45, 0.95); - backdrop-filter: blur(15px); - border: 1px solid rgba(0, 255, 200, 0.3); - border-radius: 8px; - color: #00ffc8; - font-size: 20px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.3s; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); - - &:hover { - background: rgba(0, 255, 200, 0.2); - border-color: rgba(0, 255, 200, 0.5); - transform: translateY(-2px); - box-shadow: 0 6px 25px rgba(0, 255, 200, 0.3); - } - - &:active { - transform: translateY(0); - } - - &.active { - background: rgba(0, 255, 200, 0.3); - border-color: #00ffc8; - box-shadow: 0 0 25px rgba(0, 255, 200, 0.6); - } -} - -/* 滚动条样式 */ -.device-panel::-webkit-scrollbar, -.map-canvas-wrapper::-webkit-scrollbar { - width: 10px; - height: 10px; -} - -.device-panel::-webkit-scrollbar-track, -.map-canvas-wrapper::-webkit-scrollbar-track { - background: rgba(0, 0, 0, 0.2); -} - -.device-panel::-webkit-scrollbar-thumb, -.map-canvas-wrapper::-webkit-scrollbar-thumb { - background: rgba(0, 255, 200, 0.3); - border-radius: 5px; - - &:hover { - background: rgba(0, 255, 200, 0.5); - } -} - -.map-canvas-wrapper::-webkit-scrollbar-corner { - background: rgba(0, 0, 0, 0.2); -} diff --git a/nl-vue/src/views/nl_agv/map/index.vue b/nl-vue/src/views/nl_agv/map/index.vue new file mode 100644 index 0000000..3743d59 --- /dev/null +++ b/nl-vue/src/views/nl_agv/map/index.vue @@ -0,0 +1,528 @@ + + + + + diff --git a/src/views/nl_agv/layout/components/DeviceMarker.vue b/src/views/nl_agv/layout/components/DeviceMarker.vue new file mode 100644 index 0000000..188f096 --- /dev/null +++ b/src/views/nl_agv/layout/components/DeviceMarker.vue @@ -0,0 +1,398 @@ + + + + + diff --git a/src/views/nl_agv/layout/index.vue b/src/views/nl_agv/layout/index.vue new file mode 100644 index 0000000..5be084a --- /dev/null +++ b/src/views/nl_agv/layout/index.vue @@ -0,0 +1,609 @@ + + + + +