@yangyongtao/gaea 1.1.9 → 1.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -10
- package/USAGE.md +200 -0
- package/package.json +8 -2
- package/public/image/CommonDialog/icon-/345/272/223/345/256/271@2x.png +0 -0
- package/public/image/CommonDialog/icon-/346/260/264/344/275/215@2x.png +0 -0
- package/public/image/CommonDialog/icon-/351/233/250/351/207/217@2x.png +0 -0
- package/public/image/CommonDialog//345/274/271/347/252/227_bg.png +0 -0
- package/public/image/CommonDialog//345/274/271/347/252/227/346/240/207/351/242/230/350/203/214/346/231/257.png +0 -0
- package/public/image/CommonDialog//345/274/271/347/252/227/346/240/207/351/242/230/350/243/205/351/245/260@2x.png +0 -0
- package/public/static/css/main.css +111 -0
- package/src/GaeaMethods.js +1473 -7
- package/src/components/CommonDialog.vue +289 -0
- package/src/components/FlyAlongRoute.vue +35 -45
- package/src/components/HydrologicStationDialog.vue +435 -0
- package/src/components/LayerTree.vue +264 -0
- package/src/components/SecTourView.vue +83 -0
- package/src/components/WaterGateTour.vue +121 -0
- package/src/components/WeatherControl.vue +2 -2
- package/src/components/index.js +5 -0
- package/src/components/pathChart.vue +282 -0
- package/src/components/swiperSecAnimation.vue +208 -0
- package/src/vite-plugin.js +5 -2
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<swiperSecAnimation
|
|
3
|
+
v-if="visible"
|
|
4
|
+
class="swiperSec"
|
|
5
|
+
:total="animationData.length"
|
|
6
|
+
:initialIndex="animationData.length - 1"
|
|
7
|
+
@index-change="handleIndexChange"
|
|
8
|
+
/>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
|
13
|
+
import swiperSecAnimation from './swiperSecAnimation.vue';
|
|
14
|
+
|
|
15
|
+
const visible = ref(false);
|
|
16
|
+
const animationData = ref([]);
|
|
17
|
+
let currentIndex = 0;
|
|
18
|
+
let tourElement = null;
|
|
19
|
+
|
|
20
|
+
function handleIconClick(event) {
|
|
21
|
+
const detail = event.detail || event;
|
|
22
|
+
if (detail.category !== 'secData') return;
|
|
23
|
+
console.log('[SecTourView] secData event:', 'secAnimation:', !!detail.data?.secAnimation, 'tourModel:', !!detail.tourModel);
|
|
24
|
+
if (!detail.data?.secAnimation?.length || !detail.tourModel) {
|
|
25
|
+
console.warn('[SecTourView] 跳过:secAnimation或tourModel缺失');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// 仅缓存数据,等模型锁定后再显示滚动条
|
|
29
|
+
animationData.value = detail.data.secAnimation;
|
|
30
|
+
tourElement = detail.tourModel;
|
|
31
|
+
currentIndex = animationData.value.length - 1;
|
|
32
|
+
visible.value = false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function handleSecLocked() {
|
|
36
|
+
// 模型锁定后才显示断面滚动条
|
|
37
|
+
if (!tourElement || !animationData.value.length) return;
|
|
38
|
+
visible.value = true;
|
|
39
|
+
console.log('[SecTourView] locked, visible:', visible.value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function handleIndexChange(newIndex) {
|
|
43
|
+
if (!tourElement || !animationData.value.length) return;
|
|
44
|
+
const oldIdx = currentIndex;
|
|
45
|
+
const arr = [animationData.value[oldIdx], animationData.value[newIndex]];
|
|
46
|
+
window.APP?.gtlfAnimationPlayer(arr, {
|
|
47
|
+
animationName: 'test' + currentIndex,
|
|
48
|
+
animationType: 'time',
|
|
49
|
+
animationPlaySpeed: 3,
|
|
50
|
+
animationLoop: false,
|
|
51
|
+
}, tourElement);
|
|
52
|
+
currentIndex = newIndex;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function handleReset() {
|
|
56
|
+
visible.value = false;
|
|
57
|
+
tourElement = null;
|
|
58
|
+
animationData.value = [];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onMounted(() => {
|
|
62
|
+
window.addEventListener('gaea-icon-click', handleIconClick);
|
|
63
|
+
window.addEventListener('gaea-sec-locked', handleSecLocked);
|
|
64
|
+
window.addEventListener('gaea-reset-view', handleReset);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
onBeforeUnmount(() => {
|
|
68
|
+
window.removeEventListener('gaea-icon-click', handleIconClick);
|
|
69
|
+
window.removeEventListener('gaea-sec-locked', handleSecLocked);
|
|
70
|
+
window.removeEventListener('gaea-reset-view', handleReset);
|
|
71
|
+
});
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<style>
|
|
75
|
+
.swiperSec {
|
|
76
|
+
position: absolute;
|
|
77
|
+
width: 40%;
|
|
78
|
+
bottom: 10%;
|
|
79
|
+
left: 50%;
|
|
80
|
+
transform: translateX(-50%);
|
|
81
|
+
z-index: 100;
|
|
82
|
+
}
|
|
83
|
+
</style>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="water-gate-tour-btn" @mouseenter="showMenu = true" @mouseleave="showMenu = false">
|
|
3
|
+
<button class="tour-btn">室内游览</button>
|
|
4
|
+
<div class="tour-menu" v-show="showMenu">
|
|
5
|
+
<div
|
|
6
|
+
v-for="gate in gates"
|
|
7
|
+
:key="gate"
|
|
8
|
+
class="tour-menu-item"
|
|
9
|
+
@click="startTour(gate)"
|
|
10
|
+
>{{ gate }}</div>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<!-- 路径节点组件(挂在外层,避免受按钮 hover 影响) -->
|
|
15
|
+
<pathChart
|
|
16
|
+
v-if="tourActive"
|
|
17
|
+
class="tourPath"
|
|
18
|
+
:locations="positionList"
|
|
19
|
+
:currentIndex="currentIndex"
|
|
20
|
+
@node-click="handleNodeClick"
|
|
21
|
+
direction="horizontal"
|
|
22
|
+
/>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup>
|
|
26
|
+
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
|
27
|
+
import pathChart from './pathChart.vue';
|
|
28
|
+
|
|
29
|
+
const gates = ['沿浦水闸', '联盟水闸', '下在水闸', '岭尾新闸', '岭尾水闸'];
|
|
30
|
+
const showMenu = ref(false);
|
|
31
|
+
const tourActive = ref(false);
|
|
32
|
+
const positionList = ref([]);
|
|
33
|
+
const currentIndex = ref(0);
|
|
34
|
+
|
|
35
|
+
function startTour(gate) {
|
|
36
|
+
const app = window.APP;
|
|
37
|
+
if (!app) return;
|
|
38
|
+
const cfg = app._tourConfig?.[gate];
|
|
39
|
+
if (!cfg) return;
|
|
40
|
+
app.initModelTour(gate, cfg.direction);
|
|
41
|
+
positionList.value = cfg.positionList || [];
|
|
42
|
+
currentIndex.value = 0;
|
|
43
|
+
tourActive.value = positionList.value.length > 0;
|
|
44
|
+
showMenu.value = false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function handleNodeClick(index) {
|
|
48
|
+
window.APP?.tourNodeClick(positionList.value, index);
|
|
49
|
+
currentIndex.value = index;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function handleReset() {
|
|
53
|
+
tourActive.value = false;
|
|
54
|
+
positionList.value = [];
|
|
55
|
+
currentIndex.value = 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
onMounted(() => {
|
|
59
|
+
window.addEventListener('gaea-reset-view', handleReset);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
onBeforeUnmount(() => {
|
|
63
|
+
window.removeEventListener('gaea-reset-view', handleReset);
|
|
64
|
+
});
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<style scoped>
|
|
68
|
+
.water-gate-tour-btn {
|
|
69
|
+
position: relative;
|
|
70
|
+
display: inline-block;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.tour-btn {
|
|
74
|
+
padding: 8px 16px;
|
|
75
|
+
border: none;
|
|
76
|
+
border-radius: 6px;
|
|
77
|
+
background: #3b82f6;
|
|
78
|
+
color: #fff;
|
|
79
|
+
cursor: pointer;
|
|
80
|
+
font-size: 14px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.tour-btn:hover {
|
|
84
|
+
background: #2563eb;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.tour-menu {
|
|
88
|
+
position: absolute;
|
|
89
|
+
top: 100%;
|
|
90
|
+
left: 0;
|
|
91
|
+
padding-top: 4px;
|
|
92
|
+
background: transparent;
|
|
93
|
+
min-width: 120px;
|
|
94
|
+
z-index: 1000;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.tour-menu-item {
|
|
98
|
+
padding: 8px 16px;
|
|
99
|
+
color: #fff;
|
|
100
|
+
font-size: 14px;
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
white-space: nowrap;
|
|
103
|
+
background: rgba(1, 79, 152, 0.95);
|
|
104
|
+
transition: background 0.15s;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.tour-menu-item:first-child { border-radius: 6px 6px 0 0; }
|
|
108
|
+
.tour-menu-item:last-child { border-radius: 0 0 6px 6px; }
|
|
109
|
+
|
|
110
|
+
.tour-menu-item:hover {
|
|
111
|
+
background: #007ffd;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.tourPath {
|
|
115
|
+
position: fixed;
|
|
116
|
+
bottom: 30px;
|
|
117
|
+
left: 50%;
|
|
118
|
+
transform: translateX(-50%);
|
|
119
|
+
z-index: 1000;
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
@@ -239,7 +239,7 @@ const loadTyphoonRoute = async () => {
|
|
|
239
239
|
typhoonPicking.value = false;
|
|
240
240
|
typhoonLoading.value = true;
|
|
241
241
|
try {
|
|
242
|
-
await APP.
|
|
242
|
+
await APP.addTyphoonRoute(typhoonPoints.value);
|
|
243
243
|
} catch (error) {
|
|
244
244
|
console.error('加载台风路线错误:', error);
|
|
245
245
|
} finally {
|
|
@@ -266,7 +266,7 @@ onBeforeUnmount(() => {
|
|
|
266
266
|
position: absolute;
|
|
267
267
|
top: 100px;
|
|
268
268
|
left: 600px;
|
|
269
|
-
z-index:
|
|
269
|
+
z-index: 10000;
|
|
270
270
|
width: 300px;
|
|
271
271
|
background: rgba(15, 23, 42, 0.95);
|
|
272
272
|
border-radius: 12px;
|
package/src/components/index.js
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
export { default as WeatherControl } from './WeatherControl.vue';
|
|
2
2
|
export { default as FlyAlongRoute } from './FlyAlongRoute.vue';
|
|
3
|
+
export { default as LayerTree } from './LayerTree.vue';
|
|
4
|
+
export { default as CommonDialog } from './CommonDialog.vue';
|
|
5
|
+
export { default as HydrologicStationDialog } from './HydrologicStationDialog.vue';
|
|
6
|
+
export { default as SecTourView } from './SecTourView.vue';
|
|
7
|
+
export { default as WaterGateTour } from './WaterGateTour.vue';
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- 路径容器:支持横向/纵向布局 -->
|
|
3
|
+
<div
|
|
4
|
+
class="location-path-container"
|
|
5
|
+
:class="{ 'vertical': direction === 'vertical' }"
|
|
6
|
+
:style="{ width: width, height: direction === 'vertical' ? height : 'auto' }"
|
|
7
|
+
>
|
|
8
|
+
<!-- 横向布局 -->
|
|
9
|
+
<div class="path-wrapper-horizontal" v-if="direction === 'horizontal'">
|
|
10
|
+
<template v-for="(location, index) in locations" :key="index">
|
|
11
|
+
<!-- 单个地点项(名称+节点) -->
|
|
12
|
+
<div class="location-item">
|
|
13
|
+
<div
|
|
14
|
+
class="location-name"
|
|
15
|
+
:class="{ 'active-name': index === innerCurrentIndex }"
|
|
16
|
+
>
|
|
17
|
+
{{ location.name }}
|
|
18
|
+
</div>
|
|
19
|
+
<!-- 节点容器:固定尺寸,确保圆心位置可计算 -->
|
|
20
|
+
<div class="node-wrapper">
|
|
21
|
+
<div
|
|
22
|
+
class="location-node"
|
|
23
|
+
:class="{ 'active': index === innerCurrentIndex }"
|
|
24
|
+
:style="{
|
|
25
|
+
width: `${nodeSize}px`,
|
|
26
|
+
height: `${nodeSize}px`,
|
|
27
|
+
borderColor: lineColor,
|
|
28
|
+
backgroundColor: index === innerCurrentIndex ? activeColor : nodeColor
|
|
29
|
+
}"
|
|
30
|
+
@click="handleNodeClick(index)"
|
|
31
|
+
>
|
|
32
|
+
<span class="node-content">
|
|
33
|
+
{{ location.icon || (index + 1) }}
|
|
34
|
+
</span>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<!-- 横向连线:精准对齐节点圆心 + 整体下移 -->
|
|
39
|
+
<div
|
|
40
|
+
class="path-line line-horizontal"
|
|
41
|
+
v-if="index < locations.length - 1"
|
|
42
|
+
:style="{
|
|
43
|
+
background: lineColor,
|
|
44
|
+
width: `${lineLength}px`,
|
|
45
|
+
height: `${lineWidth}px`,
|
|
46
|
+
}"
|
|
47
|
+
></div>
|
|
48
|
+
</template>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<!-- 纵向布局 -->
|
|
52
|
+
<div class="path-wrapper-vertical" v-else>
|
|
53
|
+
<template v-for="(location, index) in locations" :key="index">
|
|
54
|
+
<!-- 单个地点项(名称+节点) -->
|
|
55
|
+
<div class="location-item">
|
|
56
|
+
<div
|
|
57
|
+
class="location-name"
|
|
58
|
+
:class="{ 'active-name': index === innerCurrentIndex }"
|
|
59
|
+
>
|
|
60
|
+
{{ location.name }}
|
|
61
|
+
</div>
|
|
62
|
+
<!-- 节点容器:固定尺寸 -->
|
|
63
|
+
<div class="node-wrapper">
|
|
64
|
+
<div
|
|
65
|
+
class="location-node"
|
|
66
|
+
:class="{ 'active': index === innerCurrentIndex }"
|
|
67
|
+
:style="{
|
|
68
|
+
width: `${nodeSize}px`,
|
|
69
|
+
height: `${nodeSize}px`,
|
|
70
|
+
borderColor: lineColor,
|
|
71
|
+
backgroundColor: index === innerCurrentIndex ? activeColor : nodeColor
|
|
72
|
+
}"
|
|
73
|
+
@click="handleNodeClick(index)"
|
|
74
|
+
>
|
|
75
|
+
<span class="node-content">
|
|
76
|
+
{{ location.icon || (index + 1) }}
|
|
77
|
+
</span>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
<!-- 纵向连线:精准对齐节点圆心 + 可选下移 -->
|
|
82
|
+
<div
|
|
83
|
+
class="path-line line-vertical"
|
|
84
|
+
v-if="index < locations.length - 1"
|
|
85
|
+
:style="{
|
|
86
|
+
background: lineColor,
|
|
87
|
+
height: `${lineLength}px`,
|
|
88
|
+
width: `${lineWidth}px`,
|
|
89
|
+
marginLeft: `calc(((${nodeSize} / 2) - (${lineWidth} / 2)))`,
|
|
90
|
+
transform: `translateY(${lineOffset}px)`
|
|
91
|
+
}"
|
|
92
|
+
></div>
|
|
93
|
+
</template>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</template>
|
|
97
|
+
|
|
98
|
+
<script setup>
|
|
99
|
+
import { defineProps, defineEmits, ref, watch } from 'vue';
|
|
100
|
+
|
|
101
|
+
const emit = defineEmits(['update:currentIndex', 'node-click']);
|
|
102
|
+
|
|
103
|
+
// 组件属性
|
|
104
|
+
const props = defineProps({
|
|
105
|
+
locations: {
|
|
106
|
+
type: Array,
|
|
107
|
+
default: () => [
|
|
108
|
+
{ name: '起点' },
|
|
109
|
+
{ name: 'A地点' },
|
|
110
|
+
{ name: 'B地点' },
|
|
111
|
+
{ name: 'C地点' },
|
|
112
|
+
{ name: '终点' }
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
currentIndex: {
|
|
116
|
+
type: Number,
|
|
117
|
+
default: 0
|
|
118
|
+
},
|
|
119
|
+
direction: {
|
|
120
|
+
type: String,
|
|
121
|
+
default: 'horizontal',
|
|
122
|
+
validator: (val) => ['horizontal', 'vertical'].includes(val)
|
|
123
|
+
},
|
|
124
|
+
width: { type: String, default: '100%' },
|
|
125
|
+
height: { type: String, default: '400px' },
|
|
126
|
+
nodeSize: { type: Number, default: 32 },
|
|
127
|
+
nodeColor: { type: String, default: '#E5E7EB' },
|
|
128
|
+
activeColor: { type: String, default: '#409EFF' },
|
|
129
|
+
lineColor: { type: String, default: '#409EFF' },
|
|
130
|
+
lineWidth: { type: Number, default: 2 },
|
|
131
|
+
lineLength: { type: Number, default: 40 },
|
|
132
|
+
activeTextColor: { type: String, default: '#409EFF' },
|
|
133
|
+
lineOffset: { type: Number, default: 0 }
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// 内部响应式选中索引(核心:模板直接用这个变量)
|
|
137
|
+
const innerCurrentIndex = ref(props.currentIndex);
|
|
138
|
+
|
|
139
|
+
// 监听父组件props变化,同步到内部
|
|
140
|
+
watch(() => props.currentIndex, (newVal) => {
|
|
141
|
+
innerCurrentIndex.value = newVal;
|
|
142
|
+
}, { immediate: true });
|
|
143
|
+
|
|
144
|
+
// 监听内部选中状态变化,通知父组件
|
|
145
|
+
watch(innerCurrentIndex, (newVal) => {
|
|
146
|
+
emit('update:currentIndex', newVal);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// 节点点击事件(添加日志,方便调试)
|
|
150
|
+
const handleNodeClick = (index) => {
|
|
151
|
+
console.log('点击了节点索引:', index); // 调试用,可删除
|
|
152
|
+
innerCurrentIndex.value = index;
|
|
153
|
+
emit('node-click', index, props.locations[index]);
|
|
154
|
+
};
|
|
155
|
+
</script>
|
|
156
|
+
|
|
157
|
+
<style scoped>
|
|
158
|
+
/* 容器基础样式 */
|
|
159
|
+
.location-path-container {
|
|
160
|
+
padding: 20px;
|
|
161
|
+
box-sizing: border-box;
|
|
162
|
+
font-family: sans-serif;
|
|
163
|
+
position: absolute;
|
|
164
|
+
bottom: 120px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* ---------------- 横向布局核心样式 ---------------- */
|
|
168
|
+
.path-wrapper-horizontal {
|
|
169
|
+
display: flex;
|
|
170
|
+
align-items: center;
|
|
171
|
+
justify-content: center;
|
|
172
|
+
flex-wrap: wrap;
|
|
173
|
+
gap: 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.path-wrapper-horizontal .location-item {
|
|
177
|
+
display: flex;
|
|
178
|
+
flex-direction: column;
|
|
179
|
+
align-items: center;
|
|
180
|
+
width: 3rem;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.path-wrapper-horizontal .node-wrapper {
|
|
184
|
+
width: v-bind(nodeSize + 'px');
|
|
185
|
+
height: v-bind(nodeSize + 'px');
|
|
186
|
+
display: flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
justify-content: center;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.line-horizontal {
|
|
192
|
+
margin: 0;
|
|
193
|
+
align-self: center;
|
|
194
|
+
transform: translate(0, 0.625rem);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* ---------------- 纵向布局核心样式 ---------------- */
|
|
198
|
+
.path-wrapper-vertical {
|
|
199
|
+
display: flex;
|
|
200
|
+
flex-direction: column;
|
|
201
|
+
gap: 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.path-wrapper-vertical .location-item {
|
|
205
|
+
display: flex;
|
|
206
|
+
flex-direction: column;
|
|
207
|
+
align-items: flex-start;
|
|
208
|
+
width: 3rem;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.path-wrapper-vertical .node-wrapper {
|
|
212
|
+
width: v-bind(nodeSize + 'px');
|
|
213
|
+
height: v-bind(nodeSize + 'px');
|
|
214
|
+
display: flex;
|
|
215
|
+
align-items: center;
|
|
216
|
+
justify-content: center;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.line-vertical {
|
|
220
|
+
margin: 0 0 0 calc((v-bind(nodeSize) / 2) - (v-bind(lineWidth) / 2));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* ---------------- 通用样式 ---------------- */
|
|
224
|
+
.location-name {
|
|
225
|
+
font-size: 14px;
|
|
226
|
+
color: #666;
|
|
227
|
+
margin-bottom: 8px;
|
|
228
|
+
transition: color 0.2s ease;
|
|
229
|
+
white-space: nowrap;
|
|
230
|
+
text-align: center;
|
|
231
|
+
}
|
|
232
|
+
.path-wrapper-vertical .location-name {
|
|
233
|
+
text-align: left;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* 强化选中名称样式优先级 */
|
|
237
|
+
.location-name.active-name {
|
|
238
|
+
color: v-bind(activeTextColor) !important;
|
|
239
|
+
font-weight: 600 !important;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/* 地点节点(强化样式优先级) */
|
|
243
|
+
.location-node {
|
|
244
|
+
border-radius: 50%;
|
|
245
|
+
border: 2px solid !important; /* 强制生效 */
|
|
246
|
+
display: flex;
|
|
247
|
+
align-items: center;
|
|
248
|
+
justify-content: center;
|
|
249
|
+
color: #fff !important; /* 强制生效 */
|
|
250
|
+
font-size: 14px;
|
|
251
|
+
font-weight: 600;
|
|
252
|
+
z-index: 2;
|
|
253
|
+
transition: all 0.2s ease;
|
|
254
|
+
margin: 0;
|
|
255
|
+
padding: 0;
|
|
256
|
+
cursor: pointer;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* 强化选中节点样式,确保覆盖默认样式 */
|
|
260
|
+
.location-node.active {
|
|
261
|
+
background-color: v-bind(activeColor) !important;
|
|
262
|
+
border-color: v-bind(activeColor) !important;
|
|
263
|
+
box-shadow: 0 0 0 4px rgba(64, 158, 255, 0.2) !important;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.location-node:hover {
|
|
267
|
+
transform: scale(1.1);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/* 未选中节点样式(兜底) */
|
|
271
|
+
.location-node:not(.active) {
|
|
272
|
+
background-color: v-bind(nodeColor) !important;
|
|
273
|
+
border-color: v-bind(lineColor) !important;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.path-line {
|
|
277
|
+
transition: opacity 0.2s ease;
|
|
278
|
+
}
|
|
279
|
+
.path-line:hover {
|
|
280
|
+
opacity: 0.8;
|
|
281
|
+
}
|
|
282
|
+
</style>
|