diff --git a/src/components/IPlayer/config.js b/src/components/IPlayer/config.js
index 3048428..a02d3d9 100644
--- a/src/components/IPlayer/config.js
+++ b/src/components/IPlayer/config.js
@@ -24,7 +24,7 @@ export const conf = {
text: '进度条信息提示...', // hover的时候展示文案,可以为空
duration: 1, // 展示时间跨度,单位为s
style: { // 指定样式
- backgroundColor: 'white'
+ backgroundColor: 'var(--color-player-marker)'
}
},
],
@@ -41,9 +41,9 @@ export const conf = {
i18n: [], // 使用默认的中文
// 自定义一些颜色
commonStyle: {
- progressColor: 'green', // 整个进度条颜色
- playedColor: 'chocolate', // 已播放的进度条颜色
- volumeColor: 'pink', // 音量大小竖向滑块颜色
+ progressColor: 'var(--color-player-progress)', // 整个进度条颜色
+ playedColor: 'var(--color-player-played-progress)', // 已播放的进度条颜色
+ volumeColor: 'var(--color-player-volume)', // 音量大小竖向滑块颜色
},
controls: true, // 是否使用底部控制栏,默认使用
miniprogress: true, // 是否使用mini进度条(当底部控制栏隐藏时生效)
diff --git a/src/components/IPlayer/index.vue b/src/components/IPlayer/index.vue
index 8b14a05..6237a2a 100644
--- a/src/components/IPlayer/index.vue
+++ b/src/components/IPlayer/index.vue
@@ -53,6 +53,7 @@ const init = () => {
.player_container {
width: 100%;
height: 100%;
+ background: $color-background-base;
.xgplayer {
height: 100% !important;
diff --git a/src/main.js b/src/main.js
index 1c845fc..d2cce40 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,5 +1,5 @@
import { createApp } from 'vue'
-import './style.css'
+import './style.scss'
import App from './App.vue'
import router from '@/router'
import { createPinia } from 'pinia'
diff --git a/src/style.css b/src/style.css
deleted file mode 100644
index 84a4633..0000000
--- a/src/style.css
+++ /dev/null
@@ -1,9 +0,0 @@
-* {
- padding: 0;
- margin: 0;
-}
-
-html,body, #app {
- width: 100%;
- height: 100%;
-}
\ No newline at end of file
diff --git a/src/style.scss b/src/style.scss
new file mode 100644
index 0000000..f6812c6
--- /dev/null
+++ b/src/style.scss
@@ -0,0 +1,39 @@
+:root {
+ --color-background-base: #{$color-background-base};
+ --color-connection-card: #{$color-connection-card};
+ --color-canvas-grid-line: #{$color-canvas-grid-line};
+ --color-canvas-area-fill: #{$color-canvas-area-fill};
+ --color-canvas-area-border: #{$color-canvas-area-border};
+ --color-canvas-line-default: #{$color-canvas-line-default};
+ --color-canvas-line-forbidden: #{$color-canvas-line-forbidden};
+ --color-canvas-line-virtual: #{$color-canvas-line-virtual};
+ --color-canvas-route: #{$color-canvas-route};
+ --color-canvas-route-arrow: #{$color-canvas-route-arrow};
+ --color-canvas-curve: #{$color-canvas-curve};
+ --color-canvas-curve-arrow: #{$color-canvas-curve-arrow};
+ --color-canvas-curve-marker: #{$color-canvas-curve-marker};
+ --color-canvas-landmark: #{$color-canvas-landmark};
+ --color-canvas-charging-point: #{$color-canvas-charging-point};
+ --color-canvas-loading-point: #{$color-canvas-loading-point};
+ --color-canvas-workstation: #{$color-canvas-workstation};
+ --color-canvas-tooltip-title: #{$color-canvas-tooltip-title};
+ --color-canvas-boundary: #{$color-canvas-boundary};
+ --color-canvas-robot: #{$color-canvas-robot};
+ --color-canvas-robot-label: #{$color-canvas-robot-label};
+ --color-player-marker: #{$color-player-marker};
+ --color-player-progress: #{$color-player-progress};
+ --color-player-played-progress: #{$color-player-played-progress};
+ --color-player-volume: #{$color-player-volume};
+}
+
+* {
+ padding: 0;
+ margin: 0;
+}
+
+html,
+body,
+#app {
+ width: 100%;
+ height: 100%;
+}
diff --git a/src/styles/vars.scss b/src/styles/vars.scss
index f38d2a7..d91f4c7 100644
--- a/src/styles/vars.scss
+++ b/src/styles/vars.scss
@@ -1,42 +1,96 @@
-// 全局自定义变量
-$primary: #409eff;
+// Dark application theme
+$color-background-base: #070c11;
+$color-background-panel: #0b1218;
+$color-background-card: #101a21;
+$color-background-card-hover: #16252d;
+$color-background-header-translucent: rgba(11, 18, 24, 0.92);
+$color-background-tooltip-translucent: rgba(11, 18, 24, 0.96);
-$text: #c0cfdf;
-$text-dim: #475a72;
-$text-bright:#e8f0f8;
-$text-gray: #666;
+$color-text-primary: #c8d9e2;
+$color-text-secondary: #86a7b5;
+$color-text-bright: #edf9fc;
+$color-text-accent-soft: #b4eaf4;
+$color-text-accent-bright: #d2f4fa;
+$color-text-navigation: #a8cbd5;
+$color-text-navigation-active: #effcff;
+$color-text-tooltip: #9db9c3;
-$bg-deep: #060a12;
-$bg-body: #0a0f1a;
-$bg-card: #0f1628;
-$bg-card-hi: #141d32;
-$border: rgba(0,195,255,0.08);
-$border-hi: rgba(0,195,255,0.22);
-$accent: #00c3ff;
-$accent-dim: rgba(0,195,255,0.14);
-$danger: #ff2d55;
-$success: #00e676;
+$color-accent-primary: #66d9f7;
+$color-accent-secondary: #8ee7f9;
+$color-accent-border: rgba(102, 217, 247, 0.14);
+$color-accent-border-strong: rgba(102, 217, 247, 0.34);
+$color-accent-glow: rgba(102, 217, 247, 0.18);
+$color-accent-subtle: rgba(102, 217, 247, 0.07);
+$color-accent-soft: rgba(102, 217, 247, 0.10);
+$color-accent-medium: rgba(102, 217, 247, 0.12);
+$color-accent-selected: rgba(102, 217, 247, 0.16);
+$color-accent-border-muted: rgba(102, 217, 247, 0.20);
+$color-accent-border-header: rgba(102, 217, 247, 0.30);
+$color-accent-border-hover: rgba(102, 217, 247, 0.42);
+$color-accent-border-active: rgba(142, 231, 249, 0.72);
+$color-accent-text-muted: rgba(142, 231, 249, 0.42);
+$color-accent-radial-glow: rgba(102, 217, 247, 0.09);
+$color-accent-inset-glow: rgba(102, 217, 247, 0.06);
+$color-accent-tag-background: rgba(102, 217, 247, 0.08);
+$color-accent-core-background: rgba(102, 217, 247, 0.03);
+$color-accent-slider-glow: rgba(102, 217, 247, 0.35);
-$font-h: 'Rajdhani', sans-serif;
-$font-b: 'Noto Sans SC', 'PingFang SC', sans-serif;
-$font-m: 'JetBrains Mono', monospace;
-$radius: 10px;
-$topbar-bg: #1e2a3a;
-$topbar-text: #a8b2c7;
-$transition: 0.25s ease;
-$shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
-$text-secondary: #606266;
-$border-light: #f0f2f5;
-$text-primary: #2c3e50;
-$text-muted: #909399;
-$radius-sm: 6px;
-$primary-dark: #337ecc;
-$border-color: #e4e7ed;
+$color-danger: #ff2d55;
+$color-danger-background: rgba(255, 45, 85, 0.06);
+$color-danger-background-hover: rgba(255, 45, 85, 0.14);
+$color-success: #00e676;
+$color-axis-x: #f87171;
+$color-axis-x-background: rgba(248, 113, 113, 0.15);
+$color-axis-x-border: rgba(248, 113, 113, 0.30);
+$color-axis-y: #34d399;
+$color-axis-y-background: rgba(52, 211, 153, 0.15);
+$color-axis-y-border: rgba(52, 211, 153, 0.30);
+$color-axis-z: #38bdf8;
+$color-axis-z-background: rgba(56, 189, 248, 0.15);
+$color-axis-z-border: rgba(56, 189, 248, 0.30);
+$color-white-subtle: rgba(255, 255, 255, 0.02);
+$color-white-muted: rgba(255, 255, 255, 0.05);
+$color-shadow-soft: rgba(0, 0, 0, 0.06);
+$color-shadow-header: rgba(0, 0, 0, 0.22);
+$color-shadow-tooltip: rgba(0, 0, 0, 0.50);
-// 自定义混合
-@mixin flex-center {
- display: flex;
- align-items: center;
- justify-content: center;
-}
\ No newline at end of file
+// Connection page
+$color-connection-card: #ffffff;
+$color-connection-title: #000000;
+$color-connection-text-muted: #8f8f8f;
+$color-connection-primary: #003af7;
+$color-connection-tip-background: #b7c5f3;
+
+// Canvas and 3D visualization
+$color-canvas-grid-line: rgba(30, 50, 80, 0.25);
+$color-canvas-area-fill: rgba(224, 64, 251, 0.12);
+$color-canvas-area-border: rgba(224, 64, 251, 0.50);
+$color-canvas-line-default: #ff6e40;
+$color-canvas-line-forbidden: #ff1744;
+$color-canvas-line-virtual: #ffab40;
+$color-canvas-route: #00e5ff;
+$color-canvas-route-arrow: rgba(0, 229, 255, 0.60);
+$color-canvas-curve: #76ff03;
+$color-canvas-curve-arrow: rgba(118, 255, 3, 0.70);
+$color-canvas-curve-marker: rgba(118, 255, 3, 0.25);
+$color-canvas-landmark: #ffd600;
+$color-canvas-charging-point: #22c55e;
+$color-canvas-loading-point: #3b82f6;
+$color-canvas-workstation: #a855f7;
+$color-canvas-tooltip-title: #00e5a0;
+$color-canvas-boundary: rgba(0, 229, 160, 0.10);
+$color-canvas-robot: #00d4ff;
+$color-canvas-robot-label: #a0c0f0;
+
+// Video player controls
+$color-player-marker: #ffffff;
+$color-player-progress: #008000;
+$color-player-played-progress: #d2691e;
+$color-player-volume: #ffc0cb;
+
+$font-family-heading: 'Rajdhani', sans-serif;
+$font-family-body: 'Noto Sans SC', 'PingFang SC', sans-serif;
+$font-family-monospace: 'JetBrains Mono', monospace;
+
+$shadow-input: 0 2px 12px $color-shadow-soft;
diff --git a/src/utils/themeColors.js b/src/utils/themeColors.js
new file mode 100644
index 0000000..d614af7
--- /dev/null
+++ b/src/utils/themeColors.js
@@ -0,0 +1,2 @@
+export const getThemeColor = (propertyName) =>
+ getComputedStyle(document.documentElement).getPropertyValue(propertyName).trim()
diff --git a/src/views/Address.vue b/src/views/Address.vue
index d7bd978..fb62453 100644
--- a/src/views/Address.vue
+++ b/src/views/Address.vue
@@ -99,20 +99,20 @@ const testConnect = async () => {
.card {
padding: 40px;
box-sizing: border-box;
- background: #fff;
+ background: $color-connection-card;
width: 600px;
border-radius: 20px;
.title {
font-size: 40px;
font-weight: bold;
- color: #000;
+ color: $color-connection-title;
margin-bottom: 12px;
}
.secondaryTitle {
font-size: 20px;
- color: #8f8f8f;
+ color: $color-connection-text-muted;
margin-bottom: 8px;
}
@@ -120,8 +120,8 @@ const testConnect = async () => {
display: inline-block;
font-size: 14px;
padding: 4px 16px;
- color: #003af7;
- background: #b7c5f3;
+ color: $color-connection-primary;
+ background: $color-connection-tip-background;
border-radius: 12px;
margin-bottom: 12px;
}
@@ -135,8 +135,8 @@ const testConnect = async () => {
height: 50px;
display: inline-block;
padding: 4px 20px;
- color: #fff;
- background: #003af7;
+ color: $color-connection-card;
+ background: $color-connection-primary;
border-radius: 12px;
margin-top: 20px;
}
@@ -144,9 +144,9 @@ const testConnect = async () => {
.error-tips {
text-align: center;
font-size: 14px;
- color: #8f8f8f;
+ color: $color-connection-text-muted;
margin-top: 10px;
}
}
}
-
\ No newline at end of file
+
diff --git a/src/views/Home.vue b/src/views/Home.vue
index d4e3d98..01c2fc0 100644
--- a/src/views/Home.vue
+++ b/src/views/Home.vue
@@ -96,14 +96,18 @@ onUnmounted(() => {
.common-layout {
width: 100%;
height: 100%;
+ background: $color-background-base;
+ color: $color-text-primary;
.el-container {
width: 100%;
height: 100%;
- background-color: #000d2e;
+ background: radial-gradient(circle at 50% -20%, $color-accent-radial-glow, transparent 38%), $color-background-base;
.el-header {
- border-bottom: 1px solid #00c2ff4d;
+ background: $color-background-header-translucent;
+ border-bottom: 1px solid $color-accent-border-header;
+ box-shadow: 0 6px 24px $color-shadow-header;
}
.header-container {
@@ -116,7 +120,7 @@ onUnmounted(() => {
display: flex;
align-items: center;
justify-content: center;
- color: #00c2ff;
+ color: $color-accent-secondary;
cursor: pointer;
}
@@ -130,7 +134,7 @@ onUnmounted(() => {
align-items: center;
justify-content: center;
gap: 20px;
- color: #00c2ff;
+ color: $color-text-accent-soft;
font-size: 16px;
font-weight: 600;
letter-spacing: 2px;
@@ -149,7 +153,8 @@ onUnmounted(() => {
font-size: 26px;
font-weight: 700;
text-align: center;
- color: #00c2ff;
+ color: $color-text-accent-bright;
+ text-shadow: 0 0 18px $color-accent-border-strong;
letter-spacing: 4px;
white-space: nowrap;
}
@@ -166,22 +171,28 @@ onUnmounted(() => {
gap: 12px ;
.nav-btn {
- background: #003c8c80;
- border: 1px solid rgba(0, 194, 255, 0.35);
- color: #a0d8f0;
+ background: $color-accent-subtle;
+ border: 1px solid $color-accent-border-muted;
+ color: $color-text-navigation;
padding: 6px 20px;
border-radius: 3px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
white-space: nowrap;
+
+ &:hover {
+ border-color: $color-accent-border-hover;
+ color: $color-text-accent-bright;
+ background: $color-accent-medium;
+ }
}
.active {
- background: rgba(0, 120, 220, 0.7);
- border-color: #00c2ff;
- color: #fff;
- box-shadow: 0 0 10px rgba(0, 194, 255, 0.5);
+ background: $color-accent-selected;
+ border-color: $color-accent-border-active;
+ color: $color-text-navigation-active;
+ box-shadow: 0 0 14px $color-accent-glow, inset 0 0 12px $color-accent-inset-glow;
}
}
}
@@ -192,7 +203,7 @@ onUnmounted(() => {
justify-content: center;
font-family: 'Orbitron', monospace;
font-size: 14px;
- color: #00c2ff4d;
+ color: $color-accent-text-muted;
letter-spacing: 2px;
white-space: nowrap;
overflow: hidden;
@@ -205,4 +216,4 @@ onUnmounted(() => {
}
}
-
\ No newline at end of file
+
diff --git a/src/views/arm/MechanicalArm.vue b/src/views/arm/MechanicalArm.vue
index 09580b9..e0cd33d 100644
--- a/src/views/arm/MechanicalArm.vue
+++ b/src/views/arm/MechanicalArm.vue
@@ -437,9 +437,9 @@ onUnmounted(() => {
\ No newline at end of file
+
diff --git a/src/views/arm/UrdfView.vue b/src/views/arm/UrdfView.vue
index 8513698..ddfca72 100644
--- a/src/views/arm/UrdfView.vue
+++ b/src/views/arm/UrdfView.vue
@@ -14,6 +14,7 @@ import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
import { XacroAdapter } from '@/adapters/XacroAdapter.js'
import { fileNameMap } from './config'
+import { getThemeColor } from '@/utils/themeColors.js'
const props = defineProps({
filePath: {
@@ -40,7 +41,7 @@ const initScene = () => {
const height = container.clientHeight || 600;
scene = new THREE.Scene();
- scene.background = new THREE.Color('#060a12');
+ scene.background = new THREE.Color(getThemeColor('--color-background-base'));
camera = new THREE.PerspectiveCamera(35, width / height, 0.1, 1000);
camera.position.set(0, 0, 4);
@@ -210,7 +211,7 @@ defineExpose({ updateJoint, resetJoints, jointControls });
height: 100%;
position: relative;
overflow: hidden;
- background: #0d0d1a;
+ background: $color-background-base;
.viewer-container {
width: 100%;
@@ -227,4 +228,4 @@ defineExpose({ updateJoint, resetJoints, jointControls });
-
\ No newline at end of file
+
diff --git a/src/views/camera/index.vue b/src/views/camera/index.vue
index f8388d5..8dffc60 100644
--- a/src/views/camera/index.vue
+++ b/src/views/camera/index.vue
@@ -10,5 +10,6 @@ import IPlayer from '@/components/IPlayer/index.vue'
.page-container {
width: 100%;
height: 100%;
+ background: $color-background-base;
}
-
\ No newline at end of file
+
diff --git a/src/views/chassis/Chassis.vue b/src/views/chassis/Chassis.vue
index 7f1a331..74bbc96 100644
--- a/src/views/chassis/Chassis.vue
+++ b/src/views/chassis/Chassis.vue
@@ -13,14 +13,14 @@
@@ -207,9 +207,9 @@ function onRelease() {
display: flex;
flex-direction: column;
height: 100%;
- background: #030729;
- color: $text;
- font-family: $font-b;
+ background: $color-background-base;
+ color: $color-text-primary;
+ font-family: $font-family-body;
overflow: hidden;
user-select: none;
@@ -224,7 +224,7 @@ function onRelease() {
display: flex;
flex-direction: column;
min-width: 0;
- border-right: 1px solid $border;
+ border-right: 1px solid $color-accent-border;
.area-bar {
display: flex;
@@ -232,19 +232,19 @@ function onRelease() {
justify-content: space-between;
height: 40px;
padding: 0 16px;
- background: #030729;
- border-bottom: 1px solid $border;
+ background: $color-background-panel;
+ border-bottom: 1px solid $color-accent-border;
flex-shrink: 0;
&__title {
display: flex;
align-items: center;
gap: 8px;
- font-family: $font-h;
+ font-family: $font-family-heading;
font-size: 13px;
font-weight: 700;
letter-spacing: 1.5px;
- color: $text-dim;
+ color: $color-text-secondary;
text-transform: uppercase;
}
@@ -267,14 +267,14 @@ function onRelease() {
width: 32px;
height: 32px;
border-radius: 8px;
- background: #1E3A5F;
+ background: $color-accent-soft;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid transparent;
&:hover {
- border-color: #00D4FF;
+ border-color: $color-accent-primary;
cursor: pointer;
}
}
@@ -282,13 +282,13 @@ function onRelease() {
:deep(.el-button) {
font-size: 12px;
- color: $text-dim;
- border-color: $border;
+ color: $color-text-secondary;
+ border-color: $color-accent-border;
background: transparent;
&:hover {
- color: $accent;
- border-color: $border-hi;
+ color: $color-accent-primary;
+ border-color: $color-accent-border-strong;
}
}
}
@@ -297,7 +297,7 @@ function onRelease() {
flex: 1;
position: relative;
overflow: hidden;
- background: $bg-deep;
+ background: $color-background-base;
// canvas {
// position: absolute;
@@ -313,11 +313,11 @@ function onRelease() {
flex-direction: column;
gap: 0;
overflow-y: auto;
- background: $bg-body;
+ background: $color-background-panel;
.card {
padding: 18px 20px;
- border-bottom: 1px solid $border;
+ border-bottom: 1px solid $color-accent-border;
&__head {
display: flex;
@@ -326,11 +326,11 @@ function onRelease() {
margin-bottom: 16px;
h3 {
- font-family: $font-h;
+ font-family: $font-family-heading;
font-size: 14px;
font-weight: 700;
letter-spacing: 1.2px;
- color: $text-dim;
+ color: $color-text-secondary;
margin: 0;
text-transform: uppercase;
}
@@ -339,9 +339,9 @@ function onRelease() {
:deep(.el-tag) {
font-size: 10px;
height: 20px;
- background: rgba(0,195,255,0.08);
- border-color: $border;
- color: $accent;
+ background: $color-accent-tag-background;
+ border-color: $color-accent-border;
+ color: $color-accent-primary;
}
.dpad {
@@ -358,10 +358,10 @@ function onRelease() {
align-items: center;
justify-content: center;
gap: 4px;
- border: 1px solid $border;
+ border: 1px solid $color-accent-border;
border-radius: 8px;
- background: $bg-card;
- color: $text;
+ background: $color-background-card;
+ color: $color-text-primary;
cursor: pointer;
transition: all .15s ease;
@@ -373,24 +373,24 @@ function onRelease() {
small {
font-size: 10px;
letter-spacing: .5px;
- color: $text-dim;
+ color: $color-text-secondary;
}
&:hover {
- border-color: $border-hi;
- background: $bg-card-hi;
- color: $accent;
+ border-color: $color-accent-border-strong;
+ background: $color-background-card-hover;
+ color: $color-accent-primary;
}
&:active {
- background: $accent;
- color: $bg-deep;
- border-color: $accent;
- box-shadow: 0 0 24px $accent-dim;
+ background: $color-accent-primary;
+ color: $color-background-base;
+ border-color: $color-accent-primary;
+ box-shadow: 0 0 24px $color-accent-glow;
transform: scale(.94);
small {
- color: $bg-deep;
+ color: $color-background-base;
}
}
@@ -421,15 +421,15 @@ function onRelease() {
display: flex;
align-items: center;
justify-content: center;
- border: 1px solid $border;
+ border: 1px solid $color-accent-border;
border-radius: 8px;
- background: rgba(0,195,255,0.03);
+ background: $color-accent-core-background;
span {
width: 10px;
height: 10px;
border-radius: 50%;
- background: $accent;
+ background: $color-accent-primary;
opacity: .3;
}
}
@@ -441,12 +441,12 @@ function onRelease() {
font-size: 14px;
font-weight: 600;
letter-spacing: 1px;
- border-color: $danger !important;
- color: $danger !important;
- background: rgba(255,45,85,0.06) !important;
+ border-color: $color-danger !important;
+ color: $color-danger !important;
+ background: $color-danger-background !important;
&:hover {
- background: rgba(255,45,85,0.14) !important;
+ background: $color-danger-background-hover !important;
}
}
@@ -463,25 +463,25 @@ function onRelease() {
align-items: baseline;
margin-bottom: 8px;
font-size: 13px;
- color: $text-dim;
+ color: $color-text-secondary;
}
&__val {
- font-family: $font-m;
+ font-family: $font-family-monospace;
font-size: 13px;
font-weight: 500;
- color: $accent;
+ color: $color-accent-primary;
}
:deep(.el-slider) {
.el-slider__runway {
height: 4px;
- background: rgba(255,255,255,0.05);
+ background: $color-white-muted;
border-radius: 2px;
}
.el-slider__bar {
height: 4px;
- background: $accent;
+ background: $color-accent-primary;
border-radius: 2px;
}
.el-slider__button-wrapper {
@@ -490,13 +490,13 @@ function onRelease() {
.el-slider__button {
width: 14px;
height: 14px;
- border: 2px solid $accent;
- background: $bg-deep;
- box-shadow: 0 0 8px $accent-dim;
+ border: 2px solid $color-accent-primary;
+ background: $color-background-base;
+ box-shadow: 0 0 8px $color-accent-glow;
transition: box-shadow .2s;
&:hover {
- box-shadow: 0 0 14px rgba(0,195,255,0.35);
+ box-shadow: 0 0 14px $color-accent-slider-glow;
}
}
}
@@ -511,8 +511,8 @@ function onRelease() {
gap: 16px;
height: 38px;
padding: 0 24px;
- background: $bg-card;
- border-top: 1px solid $border;
+ background: $color-background-card;
+ border-top: 1px solid $color-accent-border;
flex-shrink: 0;
.chip {
@@ -521,27 +521,31 @@ function onRelease() {
gap: 8px;
padding: 3px 12px;
border-radius: 4px;
- background: rgba(255,255,255,0.02);
- border: 1px solid $border;
+ background: $color-white-subtle;
+ border: 1px solid $color-accent-border;
&__label {
font-size: 10px;
- color: $text-dim;
+ color: $color-text-secondary;
letter-spacing: .5px;
}
&__val {
- font-family: $font-m;
+ font-family: $font-family-monospace;
font-size: 11px;
- color: $text-bright;
+ color: $color-text-bright;
font-weight: 500;
&--ok {
- color: $success;
+ color: $color-success;
}
}
}
}
}
-
\ No newline at end of file
+.map-action-icon {
+ color: $color-canvas-robot;
+}
+
+
diff --git a/src/views/chassis/MapCanvas.vue b/src/views/chassis/MapCanvas.vue
index b65977b..1c97983 100644
--- a/src/views/chassis/MapCanvas.vue
+++ b/src/views/chassis/MapCanvas.vue
@@ -28,6 +28,7 @@ import {
import { getCurrentMap, getRobotState } from '@/api/agv.js'
import { ElMessage } from 'element-plus';
import { useRobotStore } from '@/stores/robot'
+import { getThemeColor } from '@/utils/themeColors.js'
const props = defineProps({
mapName: {
@@ -223,7 +224,7 @@ function renderFrame(timestamp) {
drawAdvancedAreaList(canvasCtx, map, applicationState)
}
- // 图层4: normalLineList(基础直线,青色 #00e5ff)
+ // 图层4: normalLineList(基础青色直线)
if (layers.normalLines) {
drawNormalLines(canvasCtx, map, applicationState);
}
@@ -233,7 +234,7 @@ function renderFrame(timestamp) {
drawAdvancedLineList(canvasCtx, map, applicationState);
}
- // 图层6: advancedCurveList(贝塞尔曲线路径,酸绿色 #76ff03)
+ // 图层6: advancedCurveList(酸绿色贝塞尔曲线路径)
if (layers.curves) {
drawAdvancedCurveList(canvasCtx, map, applicationState);
}
@@ -345,7 +346,7 @@ const updateTooltipDisplay = (hitResult) => {
朝向: ${(robot.angle * 180 / Math.PI).toFixed(1)}°
ID: ${robot.id}
`;
}
- tooltipEl.innerHTML = `${title}
${details}`;
+ tooltipEl.innerHTML = `${title}
${details}`;
tooltipEl.style.display = 'block';
tooltipEl.style.left = Math.min(applicationState.mouseState.screenX + 14, applicationState.canvasWidthPx - 220) + 'px';
tooltipEl.style.top = Math.max(4, applicationState.mouseState.screenY - 8) + 'px';
@@ -424,7 +425,7 @@ watch(() => props.mapName,
async (newVal) => {
if (newVal) {
await loadSourceMap(newVal)
- addRobot(robotStore.ip, robotStore.ip, robotStore.position.x, robotStore.position.y, robotStore.position.theta, '#00D4FF')
+ addRobot(robotStore.ip, robotStore.ip, robotStore.position.x, robotStore.position.y, robotStore.position.theta, getThemeColor('--color-canvas-robot'))
requestAnimationFrame(renderFrame);
window.addEventListener('resize', resizeCanvasToContainer); // 监听窗口大小变化
resizeCanvasToContainer(); // 初始调用一次
@@ -454,8 +455,8 @@ onUnmounted(() => {
#tooltip {
position: absolute;
display: none;
- background: #0b1120;
- border: 1px solid #2a3a5c;
+ background: $color-background-tooltip-translucent;
+ border: 1px solid $color-accent-border-header;
padding: 8px 12px;
border-radius: 3px;
pointer-events: none;
@@ -463,20 +464,21 @@ onUnmounted(() => {
font-size: 10px;
min-width: 180px;
max-width: 280px;
- box-shadow: 0 4px 16px rgba(0, 0, 0, .5);
+ box-shadow: 0 4px 16px $color-shadow-tooltip;
.tooltip-title {
font-weight: 700;
font-size: 11px;
margin-bottom: 5px;
+ color: $color-canvas-tooltip-title;
}
:deep(.tooltip-detail) {
- color: #94a3b8;
+ color: $color-text-tooltip;
padding: 2px 0;
font-size: 9px;
word-break: break-all;
}
}
}
-
\ No newline at end of file
+
diff --git a/src/views/chassis/canvasUtils.js b/src/views/chassis/canvasUtils.js
index b85e588..bb38f23 100644
--- a/src/views/chassis/canvasUtils.js
+++ b/src/views/chassis/canvasUtils.js
@@ -1,6 +1,8 @@
+import { getThemeColor } from '@/utils/themeColors.js';
+
/**
* 6位十六进制颜色字符串转为 CSS rgba 字符串
- * @param {string} hex - 如 "#ff6e40"
+ * @param {string} hexString - 六位十六进制颜色字符串
* @param {number} alpha - 透明度 0~1
* @returns {string} CSS rgba 字符串
*/
@@ -61,7 +63,7 @@ export const decodeArgbInteger = (argbInt) => {
* 将 decodeArgbInteger 的结果转为 CSS rgba() 字符串
* @param {{r,g,b,a}} colorObj - RGBA 分量对象
* @param {number} [alphaOverride] - 可选,覆盖 alpha 值(0~1)
- * @returns {string|null} CSS rgba 字符串,如 "rgba(255,0,64,0.3)"
+ * @returns {string|null} CSS rgba 颜色字符串
*/
export const toCssRgba = (colorObj, alphaOverride) => {
if (!colorObj) return null; // 空对象返回 null
@@ -108,7 +110,7 @@ export const drawGridlines = (canvasCtx, dataStore) => {
const viewMaxY = Math.ceil(Math.max(viewTopLeft.y, viewBottomRight.y)); // 可视Y最大整数
// 绘制1米间隔的浅色网格线
- canvasCtx.strokeStyle = 'rgba(30,50,80,0.25)'; // 淡蓝灰色
+ canvasCtx.strokeStyle = getThemeColor('--color-canvas-grid-line');
canvasCtx.lineWidth = 0.5; // 细线
canvasCtx.beginPath();
for (let worldX = viewMinX; worldX <= viewMaxX; worldX++) { // 逐列绘制垂直线
@@ -138,8 +140,8 @@ export const drawAdvancedAreaList = (canvasCtx, map, dataStore) => {
if (vertices.length < 3) continue; // 少于3个顶点无法构成多边形,跳过
// ── 颜色:优先使用 attribute 中的 ARGB 整数,否则用默认品红色 ──
- let fillColorCss = 'rgba(224,64,251,0.12)'; // 默认填充(品红半透明)
- let strokeColorCss = 'rgba(224,64,251,0.5)'; // 默认描边(品红较不透明)
+ let fillColorCss = getThemeColor('--color-canvas-area-fill');
+ let strokeColorCss = getThemeColor('--color-canvas-area-border');
if (area.attribute) {
const brushColor = decodeArgbInteger(area.attribute.colorBrush); // 解码填充色
const penColor = decodeArgbInteger(area.attribute.colorPen); // 解码描边色
@@ -196,14 +198,14 @@ export const drawAdvancedLineList = (canvasCtx, map, dataStore) => {
const endScreen = worldToScreen(lineData.endPos.x, lineData.endPos.y, store);
// ── 根据 className 决定颜色和线型 ──
- let lineColorHex = '#ff6e40'; // 默认橙色
+ let lineColorHex = getThemeColor('--color-canvas-line-default');
let lineDashPattern = []; // 默认实线(无虚线)
const classNameLower = (advLine.className || '').toLowerCase();
if (classNameLower.includes('forbidden')) { // 禁行线 → 红色虚线
- lineColorHex = '#ff1744';
+ lineColorHex = getThemeColor('--color-canvas-line-forbidden');
lineDashPattern = [8, 4]; // 虚线模式:8px实 4px空
} else if (classNameLower.includes('virtual')) { // 虚拟线 → 橙色虚线
- lineColorHex = '#ffab40';
+ lineColorHex = getThemeColor('--color-canvas-line-virtual');
lineDashPattern = [4, 4];
}
@@ -247,9 +249,9 @@ export const drawNormalLines = (canvasCtx, map, dataStore) => {
// 绘制发光直线
canvasCtx.save();
- canvasCtx.shadowColor = '#00e5ff'; // 阴影颜色(产生辉光)
+ canvasCtx.shadowColor = getThemeColor('--color-canvas-route');
canvasCtx.shadowBlur = 5; // 辉光扩散半径
- canvasCtx.strokeStyle = '#00e5ff'; // 线条颜色:青色
+ canvasCtx.strokeStyle = getThemeColor('--color-canvas-route');
canvasCtx.lineWidth = 2; // 线宽
canvasCtx.globalAlpha = 0.8; // 80%不透明
canvasCtx.beginPath();
@@ -263,7 +265,7 @@ export const drawNormalLines = (canvasCtx, map, dataStore) => {
const midpointY = (startScreen.y + endScreen.y) / 2; // 中点Y
const arrowAngle = Math.atan2(endScreen.y - startScreen.y, endScreen.x - startScreen.x); // 线段方向角
const arrowLength = 5; // 箭头长度
- canvasCtx.fillStyle = 'rgba(0,229,255,0.6)'; // 箭头填充色
+ canvasCtx.fillStyle = getThemeColor('--color-canvas-route-arrow');
canvasCtx.beginPath();
canvasCtx.moveTo(midpointX + Math.cos(arrowAngle) * arrowLength, midpointY + Math.sin(arrowAngle) * arrowLength); // 箭头尖端
canvasCtx.lineTo(midpointX + Math.cos(arrowAngle + 2.5) * 4, midpointY + Math.sin(arrowAngle + 2.5) * 4); // 左翼
@@ -299,9 +301,9 @@ export const drawAdvancedCurveList = (canvasCtx, map, dataStore) => {
// ── 绘制贝塞尔曲线(虚线)──
canvasCtx.save();
- canvasCtx.shadowColor = '#76ff03'; // 酸绿色辉光
+ canvasCtx.shadowColor = getThemeColor('--color-canvas-curve');
canvasCtx.shadowBlur = 5;
- canvasCtx.strokeStyle = '#76ff03'; // 酸绿色线条
+ canvasCtx.strokeStyle = getThemeColor('--color-canvas-curve');
canvasCtx.lineWidth = 2;
canvasCtx.setLineDash([8, 5]); // 虚线模式
canvasCtx.globalAlpha = 0.85;
@@ -334,7 +336,7 @@ export const drawAdvancedCurveList = (canvasCtx, map, dataStore) => {
const tangentAngle = Math.atan2(tangentY, tangentX); // 切线角度
// 绘制箭头
- canvasCtx.fillStyle = 'rgba(118,255,3,0.7)';
+ canvasCtx.fillStyle = getThemeColor('--color-canvas-curve-arrow');
canvasCtx.beginPath();
canvasCtx.moveTo(arrowX + Math.cos(tangentAngle) * 5, arrowY + Math.sin(tangentAngle) * 5);
canvasCtx.lineTo(arrowX + Math.cos(tangentAngle + 2.5) * 4, arrowY + Math.sin(tangentAngle + 2.5) * 4);
@@ -343,7 +345,7 @@ export const drawAdvancedCurveList = (canvasCtx, map, dataStore) => {
canvasCtx.fill();
// 绘制控制点小圆(辅助调试用)
- canvasCtx.fillStyle = 'rgba(118,255,3,0.25)'; // 浅绿色半透明
+ canvasCtx.fillStyle = getThemeColor('--color-canvas-curve-marker');
for (const controlScreen of [cp1Screen, cp2Screen]) {
canvasCtx.beginPath();
canvasCtx.arc(controlScreen.x, controlScreen.y, 2.5, 0, Math.PI * 2); // 半径2.5px的小圆
@@ -353,7 +355,6 @@ export const drawAdvancedCurveList = (canvasCtx, map, dataStore) => {
// ── 曲线名称标签 ──
// canvasCtx.font = '500 7px "JetBrains Mono"';
- // canvasCtx.fillStyle = 'rgba(118,255,3,0.5)';
// canvasCtx.textAlign = 'center';
// const labelScreenY = Math.min(startScreen.y, endScreen.y) - 8; // 标签放在最高点上方
// canvasCtx.fillText(curve.instanceName || '', (startScreen.x + endScreen.x) / 2, labelScreenY);
@@ -378,18 +379,18 @@ export const drawAdvancedPointList = (canvasCtx, map, dataStore) => {
store.hoveredElement.index === pointIndex;
// ── 根据 className 决定颜色 ──
- let pointColorHex = '#ffd600'; // 默认琥珀色
+ let pointColorHex = getThemeColor('--color-canvas-landmark');
const classNameLower = (advPoint.className || '').toLowerCase();
if (classNameLower.includes('landmark') || classNameLower.includes('land')) {
- pointColorHex = '#ffd600'; // LandMark → 琥珀色
+ pointColorHex = getThemeColor('--color-canvas-landmark');
} else if (classNameLower.includes('charge')) {
- pointColorHex = '#22c55e'; // 充电点 → 绿色
+ pointColorHex = getThemeColor('--color-canvas-charging-point');
} else if (classNameLower.includes('load')) {
- pointColorHex = '#3b82f6'; // 装载点 → 蓝色
+ pointColorHex = getThemeColor('--color-canvas-loading-point');
} else if (classNameLower.includes('work') || classNameLower.includes('process')) {
- pointColorHex = '#a855f7'; // 工位 → 紫色
+ pointColorHex = getThemeColor('--color-canvas-workstation');
} else if (classNameLower.includes('station')) {
- pointColorHex = '#00e5ff'; // 站点 → 青色
+ pointColorHex = getThemeColor('--color-canvas-route');
}
// ── 绘制菱形标记 ──
@@ -413,7 +414,7 @@ export const drawAdvancedPointList = (canvasCtx, map, dataStore) => {
// 中心白色小圆点(指示精确位置)
canvasCtx.shadowBlur = 0;
- canvasCtx.fillStyle = '#fff';
+ canvasCtx.fillStyle = getThemeColor('--color-connection-card');
canvasCtx.globalAlpha = 0.9;
canvasCtx.beginPath();
canvasCtx.arc(pointScreen.x, pointScreen.y, 1.8, 0, Math.PI * 2); // 半径1.8px
@@ -457,7 +458,7 @@ export const drawMapBoundary = (canvasCtx, map, dataStore) => {
const store = dataStore ;
const boundaryTopLeft = worldToScreen(map.originX, map.maxY, store); // 边界左上角屏幕位置
const boundaryBottomRight = worldToScreen(map.maxX, map.originY, store); // 边界右下角屏幕位置
- canvasCtx.strokeStyle = 'rgba(0,229,160,0.1)'; // 极淡的青绿色
+ canvasCtx.strokeStyle = getThemeColor('--color-canvas-boundary');
canvasCtx.lineWidth = 1;
canvasCtx.setLineDash([5, 4]); // 虚线
canvasCtx.strokeRect(
@@ -555,7 +556,7 @@ export const buildOccupancyGridImage = (parsedMap, showEdgeGlow) => {
}
export class MobileRobot {
- constructor(id, name, x, y, angleRad = 0, color= "#00D4FF", imageUrl = null) {
+ constructor(id, name, x, y, angleRad = 0, color = getThemeColor('--color-canvas-robot'), imageUrl = null) {
this.id = id;
this.name = name;
this.x = x; // 世界坐标X (米)
@@ -602,7 +603,7 @@ export class MobileRobot {
}
// 名字标签
ctx.font = '12px "JetBrains Mono"';
- ctx.fillStyle = '#a0c0f0';
+ ctx.fillStyle = getThemeColor('--color-canvas-robot-label');
ctx.shadowBlur = 0;
ctx.fillText(this.name, screenX, screenY - 20);
}