feat: 统一颜色变量

This commit is contained in:
zhanghao 2026-07-21 14:00:56 +08:00
parent bb5a972111
commit 6ff7945336
15 changed files with 319 additions and 215 deletions

View File

@ -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进度条当底部控制栏隐藏时生效

View File

@ -53,6 +53,7 @@ const init = () => {
.player_container {
width: 100%;
height: 100%;
background: $color-background-base;
.xgplayer {
height: 100% !important;

View File

@ -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'

View File

@ -1,9 +0,0 @@
* {
padding: 0;
margin: 0;
}
html,body, #app {
width: 100%;
height: 100%;
}

39
src/style.scss Normal file
View File

@ -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%;
}

View File

@ -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;
}
// 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;

2
src/utils/themeColors.js Normal file
View File

@ -0,0 +1,2 @@
export const getThemeColor = (propertyName) =>
getComputedStyle(document.documentElement).getPropertyValue(propertyName).trim()

View File

@ -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;
}
}
}
</style>
</style>

View File

@ -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(() => {
}
}
</style>
</style>

View File

@ -437,9 +437,9 @@ onUnmounted(() => {
<style lang="scss" scoped>
.robot-teach-container {
height: 100%;
background: $bg-deep;
color: $text;
font-family: $font-b;
background: $color-background-base;
color: $color-text-primary;
font-family: $font-family-body;
overflow: hidden;
user-select: none;
@ -455,9 +455,8 @@ onUnmounted(() => {
width: 400px;
padding: 20px;
overflow-y: auto;
// background: #030729;
background: $bg-body;
border-right: 1px solid rgba(0, 195, 255, 0.08);
background: $color-background-panel;
border-right: 1px solid $color-accent-border;
.panel-card {
padding: 12px;
@ -471,17 +470,16 @@ onUnmounted(() => {
width: 180px;
border-radius: 5px;
padding: 6px;
background: #2d323e;
background: $color-background-card;
}
}
}
.joint-list {
margin-top: 24px;
// background: #161933;
padding: 15px;
border-radius: 8px;
color: #ccc;
color: $color-text-primary;
.title {
font-size: 20px;
@ -496,13 +494,13 @@ onUnmounted(() => {
gap: 8px;
margin-bottom: 10px;
padding: 10px;
border: 1px solid rgba(0, 195, 255, 0.08);
border: 1px solid $color-accent-border;
border-radius: 5px;
background: #0a0b10;
background: $color-background-base;
&:hover {
border-color: #2a3f7a;
background: rgba(59, 130, 246, 0.031372549);
border-color: $color-accent-border-strong;
background: $color-background-card-hover;
}
label {
@ -521,20 +519,20 @@ onUnmounted(() => {
}
:deep(.el-input-group__prepend) {
background: #080b10;
background: $color-background-base;
border-right: 0px;
box-shadow: 0 0 0 1px #272727 inset;
box-shadow: 0 0 0 1px $color-accent-border inset;
}
:deep(.el-input-group__append) {
background: #080b10;
background: $color-background-base;
border-left: 0px;
box-shadow: 0 0 0 1px #272727 inset;
box-shadow: 0 0 0 1px $color-accent-border inset;
}
:deep(.el-input__wrapper) {
background-color: #0e0e0e;
box-shadow: 0 0 0 1px #272727 inset;
background-color: $color-background-base;
box-shadow: 0 0 0 1px $color-accent-border inset;
}
}
}
@ -552,9 +550,8 @@ onUnmounted(() => {
.right-panel {
width: 400px;
padding: 20px;
// background: #030729;
background: $bg-body;
border-left: 1px solid rgba(0, 195, 255, 0.08);
background: $color-background-panel;
border-left: 1px solid $color-accent-border;
.controller {
margin-bottom: 60px;
@ -576,14 +573,14 @@ onUnmounted(() => {
align-items: center;
gap: 10px;
padding: 10px 14px;
background: #0a0b10;
border: 1px solid #1c2a52;
background: $color-background-base;
border: 1px solid $color-accent-border;
border-radius: 10px;
transition: all 0.2s ease;
&:hover {
border-color: #2a3f7a;
background: #3b82f608;
border-color: $color-accent-border-strong;
background: $color-background-card-hover;
}
.axis-label {
@ -599,21 +596,21 @@ onUnmounted(() => {
}
.x {
background: #f8717126;
color: #f87171;
border: 1px solid #f871714d;
background: $color-axis-x-background;
color: $color-axis-x;
border: 1px solid $color-axis-x-border;
}
.y {
background: #34d39926;
color: #34d399;
border: 1px solid #34d3994d;
background: $color-axis-y-background;
color: $color-axis-y;
border: 1px solid $color-axis-y-border;
}
.z {
background: #38bdf826;
color: #38bdf8;
border: 1px solid #38bdf84d;
background: $color-axis-z-background;
color: $color-axis-z;
border: 1px solid $color-axis-z-border;
}
@ -645,15 +642,15 @@ onUnmounted(() => {
// element-plus
:deep(.el-input__wrapper) {
background-color: #2d323e;
box-shadow: $shadow;
background-color: $color-background-card;
box-shadow: $shadow-input;
.el-input__inner {
color: #fff;
color: $color-text-bright;
}
}
:deep(.el-slider__runway) {
background: #333842;
background: $color-accent-medium;
}
</style>
</style>

View File

@ -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 });
</style>
</style>

View File

@ -10,5 +10,6 @@ import IPlayer from '@/components/IPlayer/index.vue'
.page-container {
width: 100%;
height: 100%;
background: $color-background-base;
}
</style>
</style>

View File

@ -13,14 +13,14 @@
</span>
<div class="map-controller">
<div class="btn-container">
<el-icon :size="16" color="#00D4FF" @click="zoomCanvas(true)"><zoom-out /></el-icon>
<el-icon :size="16" class="map-action-icon" @click="zoomCanvas(true)"><zoom-out /></el-icon>
</div>
<div class="btn-container">
<el-icon :size="16" color="#00D4FF" @click="zoomCanvas(false)"><zoom-in /></el-icon>
<el-icon :size="16" class="map-action-icon" @click="zoomCanvas(false)"><zoom-in /></el-icon>
</div>
<div class="btn-container">
<!-- @click="centerCanvasView" -->
<el-icon :size="16" color="#00D4FF" ><Location /></el-icon>
<el-icon :size="16" class="map-action-icon"><Location /></el-icon>
</div>
</div>
</div>
@ -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;
}
}
}
}
}
</style>
.map-action-icon {
color: $color-canvas-robot;
}
</style>

View File

@ -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) => {
<div class="tooltip-detail">朝向: ${(robot.angle * 180 / Math.PI).toFixed(1)}°</div>
<div class="tooltip-detail">ID: ${robot.id}</div>`;
}
tooltipEl.innerHTML = `<div class="tooltip-title" style="color:#00e5a0">${title}</div>${details}`;
tooltipEl.innerHTML = `<div class="tooltip-title">${title}</div>${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;
}
}
}
</style>
</style>

View File

@ -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);
}