|
|
|
@ -26,99 +26,79 @@ |
|
|
|
{{ $t('rightPanel.createPlan') }} |
|
|
|
</el-button> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="route-list"> |
|
|
|
<div class="tree-list"> |
|
|
|
<!-- 方案列表 --> |
|
|
|
<div |
|
|
|
v-for="plan in plans" |
|
|
|
:key="plan.id" |
|
|
|
class="route-item" |
|
|
|
class="tree-item plan-item" |
|
|
|
:class="{ selected: selectedPlanId === plan.id }" |
|
|
|
@click="handleSelectPlan(plan)" |
|
|
|
> |
|
|
|
<i class="el-icon-folder-opened"></i> |
|
|
|
<div class="route-info"> |
|
|
|
<div class="route-name">{{ plan.name }}</div> |
|
|
|
<div class="route-meta">{{ plan.routes.length }}{{ $t('rightPanel.routes') }}</div> |
|
|
|
</div> |
|
|
|
<div class="route-actions"> |
|
|
|
<i class="el-icon-edit" :title="$t('topHeader.edit.iconEdit')" @click.stop="handleOpenPlanDialog(plan)"></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-if="selectedPlanDetails" class="section"> |
|
|
|
<div class="section-header"> |
|
|
|
<div class="section-title">{{ $t('rightPanel.routeList') }}</div> |
|
|
|
<el-button |
|
|
|
type="primary" |
|
|
|
size="mini" |
|
|
|
@click="handleCreateRoute" |
|
|
|
class="create-route-btn-new" |
|
|
|
> |
|
|
|
{{ $t('rightPanel.createRoute') }} |
|
|
|
</el-button> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="route-list"> |
|
|
|
<div |
|
|
|
v-for="route in selectedPlanDetails.routes" |
|
|
|
:key="route.id" |
|
|
|
class="route-item" |
|
|
|
:class="{ selected: selectedRouteId === route.id }" |
|
|
|
@click="handleSelectRoute(route)" |
|
|
|
> |
|
|
|
<i class="el-icon-map-location"></i> |
|
|
|
<div class="route-info"> |
|
|
|
<div class="route-name">{{ route.name }}</div> |
|
|
|
<div class="route-meta">{{ route.points }}{{ $t('rightPanel.points') }}</div> |
|
|
|
</div> |
|
|
|
<el-tag |
|
|
|
v-if="route.conflict" |
|
|
|
size="mini" |
|
|
|
type="danger" |
|
|
|
class="conflict-tag" |
|
|
|
> |
|
|
|
{{ $t('rightPanel.conflict') }} |
|
|
|
</el-tag> |
|
|
|
<div class="route-actions"> |
|
|
|
<i class="el-icon-edit" :title="$t('topHeader.edit.iconEdit')" @click.stop="handleOpenRouteDialog(route)"></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-if="selectedRouteDetails" class="section"> |
|
|
|
<div class="section-title">{{ $t('rightPanel.waypointList') }}</div> |
|
|
|
<div class="waypoint-list"> |
|
|
|
<div |
|
|
|
v-for="point in selectedRouteDetails.waypoints" |
|
|
|
:key="point.name" |
|
|
|
class="waypoint-item" |
|
|
|
> |
|
|
|
<i class="el-icon-location"></i> |
|
|
|
<div class="waypoint-info"> |
|
|
|
<div class="waypoint-name">{{ point.name }}</div> |
|
|
|
<div class="waypoint-meta">{{ $t('rightPanel.altitude') }}: {{ point.altitude }}m | {{ $t('rightPanel.speed') }}: {{ point.speed }}</div> |
|
|
|
<div class="tree-item-header" @click="togglePlan(plan.id)"> |
|
|
|
<i :class="expandedPlans.includes(plan.id) ? 'el-icon-folder-opened' : 'el-icon-folder'" class="tree-icon"></i> |
|
|
|
<div class="tree-item-info"> |
|
|
|
<div class="tree-item-name">{{ plan.name }}</div> |
|
|
|
<div class="tree-item-meta">{{ routes.filter(r => r.scenarioId === plan.id).length }}个航线</div> |
|
|
|
</div> |
|
|
|
<div class="tree-item-actions"> |
|
|
|
<i class="el-icon-plus" title="新建航线" @click.stop="handleCreateRouteForPlan(plan)"></i> |
|
|
|
<i class="el-icon-edit" title="编辑" @click.stop="handleOpenPlanDialog(plan)"></i> |
|
|
|
<i class="el-icon-delete" title="删除" @click.stop="handleDeletePlan(plan)"></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="waypoint-actions"> |
|
|
|
<i class="el-icon-edit" :title="$t('topHeader.edit.iconEdit')" @click.stop="handleOpenWaypointDialog(point)"></i> |
|
|
|
<i class="el-icon-delete" :title="$t('leftMenu.delete')"></i> |
|
|
|
<!-- 航线列表 --> |
|
|
|
<div v-if="expandedPlans.includes(plan.id)" class="tree-children route-children"> |
|
|
|
<div |
|
|
|
v-for="route in routes.filter(r => r.scenarioId === plan.id)" |
|
|
|
:key="route.id" |
|
|
|
class="tree-item route-item" |
|
|
|
:class="getRouteClasses(route.id)" |
|
|
|
> |
|
|
|
<div class="tree-item-header" @click="toggleRoute(route.id)"> |
|
|
|
<i :class="expandedRoutes.includes(route.id) ? 'el-icon-map-location' : 'el-icon-map-location'" class="tree-icon"></i> |
|
|
|
<div class="tree-item-info"> |
|
|
|
<div class="tree-item-name">{{ route.name }}</div> |
|
|
|
<div class="tree-item-meta">{{ route.points }}{{ $t('rightPanel.points') }}</div> |
|
|
|
</div> |
|
|
|
<el-tag |
|
|
|
v-if="route.conflict" |
|
|
|
size="mini" |
|
|
|
type="danger" |
|
|
|
class="conflict-tag" |
|
|
|
> |
|
|
|
{{ $t('rightPanel.conflict') }} |
|
|
|
</el-tag> |
|
|
|
<div class="tree-item-actions"> |
|
|
|
<i class="el-icon-view" title="显示/隐藏" @click.stop="handleToggleRouteVisibility(route)"></i> |
|
|
|
<i class="el-icon-edit" title="编辑" @click.stop="handleOpenRouteDialog(route)"></i> |
|
|
|
<i class="el-icon-delete" title="删除" @click.stop="$emit('delete-route', route)"></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<!-- 航点列表 --> |
|
|
|
<div v-if="expandedRoutes.includes(route.id)" class="tree-children waypoint-children"> |
|
|
|
<div |
|
|
|
v-for="(point,index) in (expandedRoutes.includes(route.id) && route.waypoints ? route.waypoints : [])" |
|
|
|
:key="point.name" |
|
|
|
class="tree-item waypoint-item" |
|
|
|
> |
|
|
|
<div class="tree-item-header"> |
|
|
|
<i class="el-icon-location tree-icon"></i> |
|
|
|
<div class="tree-item-info"> |
|
|
|
<div class="tree-item-name">{{ point.name }}</div> |
|
|
|
<div class="tree-item-meta">高度: {{ point.alt }}m | 速度: {{ point.speed }}</div> |
|
|
|
</div> |
|
|
|
<div class="tree-item-actions"> |
|
|
|
<i class="el-icon-edit" title="编辑" @click.stop="handleOpenWaypointDialog(point, index, route.waypoints.length)"></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="action-buttons"> |
|
|
|
<el-button type="primary" size="mini" icon="el-icon-circle-plus" class="blue-btn" @click="handleAddWaypoint"> |
|
|
|
{{ $t('rightPanel.addWaypoint') }} |
|
|
|
</el-button> |
|
|
|
<el-button size="mini" class="blue-btn" @click="handleCancelRoute"> |
|
|
|
{{ $t('rightPanel.cancelRoute') }} |
|
|
|
</el-button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-if="activeTab === 'conflict'" class="tab-content conflict-content"> |
|
|
|
<div v-if="conflicts.length > 0" class="conflict-list"> |
|
|
|
<div |
|
|
|
@ -163,8 +143,20 @@ |
|
|
|
</el-button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-if="activeTab === 'platform'" class="tab-content platform-content"> |
|
|
|
<div class="section-header" style="padding: 10px 0; display: flex; justify-content: space-between; align-items: center;"> |
|
|
|
<div class="section-title">平台列表</div> |
|
|
|
<el-button |
|
|
|
type="primary" |
|
|
|
size="mini" |
|
|
|
icon="el-icon-upload2" |
|
|
|
@click="handleImportPlatform" |
|
|
|
class="create-route-btn-new" |
|
|
|
style="width: 90px;height: 25px;line-height: 25px;padding: 0;font-size: 14px;" |
|
|
|
> |
|
|
|
导入平台 |
|
|
|
</el-button> |
|
|
|
</div> |
|
|
|
<div class="platform-categories"> |
|
|
|
<el-tabs v-model="activePlatformTab" type="card" size="mini" class="blue-tabs"> |
|
|
|
<el-tab-pane :label="$t('rightPanel.air')" name="air"> |
|
|
|
@ -176,7 +168,11 @@ |
|
|
|
@click="handleOpenPlatformDialog(platform)" |
|
|
|
> |
|
|
|
<div class="platform-icon" :style="{ color: platform.color }"> |
|
|
|
<i :class="platform.icon"></i> |
|
|
|
<img v-if="isImg(platform.imageUrl)" |
|
|
|
:src="formatImg(platform.imageUrl)" |
|
|
|
class="platform-img" |
|
|
|
/> |
|
|
|
<i v-else :class="platform.icon || 'el-icon-picture-outline'"></i> |
|
|
|
</div> |
|
|
|
<div class="platform-info"> |
|
|
|
<div class="platform-name">{{ platform.name }}</div> |
|
|
|
@ -198,7 +194,11 @@ |
|
|
|
@click="handleOpenPlatformDialog(platform)" |
|
|
|
> |
|
|
|
<div class="platform-icon" :style="{ color: platform.color }"> |
|
|
|
<i :class="platform.icon"></i> |
|
|
|
<img v-if="isImg(platform.imageUrl)" |
|
|
|
:src="formatImg(platform.imageUrl)" |
|
|
|
class="platform-img" |
|
|
|
/> |
|
|
|
<i v-else :class="platform.icon || 'el-icon-picture-outline'"></i> |
|
|
|
</div> |
|
|
|
<div class="platform-info"> |
|
|
|
<div class="platform-name">{{ platform.name }}</div> |
|
|
|
@ -220,7 +220,11 @@ |
|
|
|
@click="handleOpenPlatformDialog(platform)" |
|
|
|
> |
|
|
|
<div class="platform-icon" :style="{ color: platform.color }"> |
|
|
|
<i :class="platform.icon"></i> |
|
|
|
<img v-if="isImg(platform.imageUrl)" |
|
|
|
:src="formatImg(platform.imageUrl)" |
|
|
|
class="platform-img" |
|
|
|
/> |
|
|
|
<i v-else :class="platform.icon || 'el-icon-picture-outline'"></i> |
|
|
|
</div> |
|
|
|
<div class="platform-info"> |
|
|
|
<div class="platform-name">{{ platform.name }}</div> |
|
|
|
@ -255,6 +259,14 @@ export default { |
|
|
|
type: Array, |
|
|
|
default: () => [] |
|
|
|
}, |
|
|
|
routes: { |
|
|
|
type: Array, |
|
|
|
default: () => [] |
|
|
|
}, |
|
|
|
activeRouteIds: { |
|
|
|
type: Array, |
|
|
|
default: () => [] |
|
|
|
}, |
|
|
|
selectedPlanId: { |
|
|
|
type: [String, Number], |
|
|
|
default: null |
|
|
|
@ -290,23 +302,129 @@ export default { |
|
|
|
groundPlatforms: { |
|
|
|
type: Array, |
|
|
|
default: () => [] |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
activePlatformTab: 'air' |
|
|
|
activePlatformTab: 'air', |
|
|
|
expandedPlans: [], // 展开的方案列表 |
|
|
|
expandedRoutes: [] // 展开的航线列表 |
|
|
|
} |
|
|
|
}, |
|
|
|
watch: { |
|
|
|
selectedPlanId(newId) { |
|
|
|
if (newId) { |
|
|
|
console.log('>>> [子组件同步] 检测到方案切换,自动展开 ID:', newId); |
|
|
|
// 如果还没展开,就把它塞进展开数组里 |
|
|
|
if (!this.expandedPlans.includes(newId)) { |
|
|
|
this.expandedPlans.push(newId); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
activeRouteIds: { |
|
|
|
handler(newVal) { |
|
|
|
console.log('activeRouteIds updated:', newVal); |
|
|
|
}, |
|
|
|
deep: true |
|
|
|
} |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
handleHide() { |
|
|
|
this.$emit('hide') |
|
|
|
// 切换方案展开/折叠 |
|
|
|
togglePlan(planId) { |
|
|
|
const index = this.expandedPlans.indexOf(planId) |
|
|
|
if (index > -1) { |
|
|
|
this.expandedPlans.splice(index, 1) |
|
|
|
const planRoutes = this.routes.filter(r => r.scenarioId === planId) |
|
|
|
planRoutes.forEach(route => { |
|
|
|
if (this.activeRouteIds.includes(route.id)) { |
|
|
|
this.handleToggleRouteVisibility(route) |
|
|
|
} |
|
|
|
}) |
|
|
|
this.$emit('select-plan', { id: null }) |
|
|
|
} else { |
|
|
|
// 展开新方案前,先清空所有已显示的航线和已展开的方案 |
|
|
|
// 清除当前地图上显示的所有航线实体(通知父组件清空 activeRouteIds 并调用地图移除方法) |
|
|
|
this.activeRouteIds.forEach(activeId => { |
|
|
|
const activeRoute = this.routes.find(r => r.id === activeId); |
|
|
|
if (activeRoute) { |
|
|
|
this.$emit('toggle-route-visibility', activeRoute); |
|
|
|
} |
|
|
|
}); |
|
|
|
// 重置展开状态,确保只有一个方案是展开的 |
|
|
|
this.expandedPlans = []; |
|
|
|
this.expandedRoutes = []; |
|
|
|
// --- 正常的展开逻辑 --- |
|
|
|
this.expandedPlans.push(planId) |
|
|
|
const plan = this.plans.find(p => p.id === planId) |
|
|
|
if (plan) { |
|
|
|
this.$emit('select-plan', plan) |
|
|
|
} |
|
|
|
// 仅加载并显示当前新方案的航线 |
|
|
|
const planRoutes = this.routes.filter(r => r.scenarioId === planId) |
|
|
|
planRoutes.forEach(route => { |
|
|
|
if (!this.activeRouteIds.includes(route.id)) { |
|
|
|
this.handleSelectRoute(route) |
|
|
|
} |
|
|
|
}) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
handleSelectPlan(plan) { |
|
|
|
this.$emit('select-plan', plan) |
|
|
|
// 切换航线展开/折叠 |
|
|
|
toggleRoute(routeId) { |
|
|
|
const route = this.routes.find(r => r.id === routeId) |
|
|
|
if (!route) return |
|
|
|
if (!route.waypoints) { |
|
|
|
this.$set(route, 'waypoints', []); // 使用 $set 确保新属性是响应式的 |
|
|
|
} |
|
|
|
const isRouteSelected = this.activeRouteIds.includes(routeId) |
|
|
|
const isRouteExpanded = this.expandedRoutes.includes(routeId) |
|
|
|
if (isRouteSelected) { |
|
|
|
if (isRouteExpanded) { |
|
|
|
const index = this.expandedRoutes.indexOf(routeId) |
|
|
|
this.expandedRoutes.splice(index, 1) |
|
|
|
} else { |
|
|
|
this.expandedRoutes.push(routeId) |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.handleSelectRoute(route) |
|
|
|
this.$nextTick(() => { |
|
|
|
// 检查当前方案是否已展开,如果没展开,可能需要先展开方案才能看到航线 |
|
|
|
if (!this.expandedPlans.includes(route.scenarioId)) { |
|
|
|
this.expandedPlans.push(route.scenarioId); |
|
|
|
} |
|
|
|
if (!this.expandedRoutes.includes(routeId)) { |
|
|
|
this.expandedRoutes.push(routeId) |
|
|
|
} |
|
|
|
}) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 判断是否是图片路径 |
|
|
|
isImg(path) { |
|
|
|
if (!path) return false; |
|
|
|
return path.includes('/') || path.includes('data:image'); |
|
|
|
}, |
|
|
|
|
|
|
|
// 格式化图片地址 |
|
|
|
formatImg(url) { |
|
|
|
if (!url) return ''; |
|
|
|
// 清理路径中的双斜杠 |
|
|
|
const cleanPath = url.replace(/\/+/g, '/'); |
|
|
|
const backendUrl = process.env.VUE_APP_BACKEND_URL; |
|
|
|
const finalUrl = backendUrl + cleanPath; |
|
|
|
|
|
|
|
// 👈 核心排查日志:按 F12 在控制台看这个输出! |
|
|
|
console.log('>>> [图片渲染调试] 最终拼接地址:', finalUrl); |
|
|
|
|
|
|
|
return finalUrl; |
|
|
|
}, |
|
|
|
|
|
|
|
handleHide() { |
|
|
|
this.$emit('hide') |
|
|
|
}, |
|
|
|
|
|
|
|
handleSelectRoute(route) { |
|
|
|
// 确保航线有航点数据 |
|
|
|
this.$emit('select-route', route) |
|
|
|
}, |
|
|
|
|
|
|
|
@ -314,28 +432,53 @@ export default { |
|
|
|
this.$emit('create-plan') |
|
|
|
}, |
|
|
|
|
|
|
|
handleCreateRoute() { |
|
|
|
this.$emit('create-route') |
|
|
|
handleCreateRouteForPlan(plan) { |
|
|
|
this.$emit('create-route', plan) |
|
|
|
}, |
|
|
|
|
|
|
|
handleDeletePlan(plan) { |
|
|
|
this.$confirm(`是否确认删除方案 "${plan.name}"?这将同时删除该方案下的所有航线。`, "警告", { |
|
|
|
confirmButtonText: "确定", |
|
|
|
cancelButtonText: "取消", |
|
|
|
type: "warning" |
|
|
|
}).then(() => { |
|
|
|
this.$emit('delete-plan', plan); |
|
|
|
}).catch(() => { |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
handleOpenPlanDialog(plan) { |
|
|
|
this.$emit('open-plan-dialog', plan) |
|
|
|
}, |
|
|
|
|
|
|
|
handleImportPlatform() { |
|
|
|
this.$emit('open-import-dialog'); |
|
|
|
}, |
|
|
|
|
|
|
|
handleOpenRouteDialog(route) { |
|
|
|
this.$emit('open-route-dialog', route) |
|
|
|
}, |
|
|
|
|
|
|
|
handleOpenWaypointDialog(point) { |
|
|
|
this.$emit('open-waypoint-dialog', point) |
|
|
|
handleToggleRouteVisibility(route) { |
|
|
|
this.$emit('toggle-route-visibility', route) |
|
|
|
// 当隐藏航线时,自动收回航点列表 |
|
|
|
const routeIndex = this.expandedRoutes.indexOf(route.id) |
|
|
|
if (routeIndex > -1) { |
|
|
|
this.expandedRoutes.splice(routeIndex, 1) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
handleAddWaypoint() { |
|
|
|
this.$emit('add-waypoint') |
|
|
|
getRouteClasses(routeId) { |
|
|
|
return { |
|
|
|
active: this.activeRouteIds.includes(routeId) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
handleCancelRoute() { |
|
|
|
this.$emit('cancel-route') |
|
|
|
handleOpenWaypointDialog(point,index,total) { |
|
|
|
this.$emit('open-waypoint-dialog', { |
|
|
|
...point, |
|
|
|
currentIndex: index, |
|
|
|
totalPoints: total |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
handleViewConflict(conflict) { |
|
|
|
@ -459,115 +602,90 @@ export default { |
|
|
|
opacity: 0.9; |
|
|
|
} |
|
|
|
|
|
|
|
.route-list { |
|
|
|
.tree-list { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.route-item { |
|
|
|
.tree-item { |
|
|
|
border-radius: 6px; |
|
|
|
transition: all 0.3s; |
|
|
|
border: 1px solid rgba(0, 138, 255, 0.1); |
|
|
|
} |
|
|
|
|
|
|
|
.tree-item-header { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 10px; |
|
|
|
padding: 10px; |
|
|
|
background: rgba(255, 255, 255, 0.8); |
|
|
|
border-radius: 6px; |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.3s; |
|
|
|
border: 1px solid rgba(0, 138, 255, 0.1); |
|
|
|
position: relative; |
|
|
|
border-radius: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.route-item:hover { |
|
|
|
.tree-item-header:hover { |
|
|
|
background: rgba(0, 138, 255, 0.1); |
|
|
|
transform: translateX(-2px); |
|
|
|
box-shadow: 0 2px 8px rgba(0, 138, 255, 0.15); |
|
|
|
} |
|
|
|
|
|
|
|
.route-item.selected { |
|
|
|
background: rgba(0, 138, 255, 0.15); |
|
|
|
border-color: rgba(0, 138, 255, 0.3); |
|
|
|
box-shadow: 0 2px 10px rgba(0, 138, 255, 0.25); |
|
|
|
.tree-item.plan-item .tree-item-header { |
|
|
|
background: rgba(255, 255, 255, 0.9) !important; |
|
|
|
} |
|
|
|
|
|
|
|
.route-info { |
|
|
|
flex: 1; |
|
|
|
.tree-item.route-item .tree-item-header { |
|
|
|
background: rgba(255, 255, 255, 0.8) !important; |
|
|
|
} |
|
|
|
|
|
|
|
.route-name { |
|
|
|
font-size: 14px; |
|
|
|
font-weight: 500; |
|
|
|
color: #333; |
|
|
|
.tree-item.route-item:not(.active) .tree-item-header { |
|
|
|
background: rgba(255, 255, 255, 0.8) !important; |
|
|
|
} |
|
|
|
|
|
|
|
.route-meta { |
|
|
|
font-size: 12px; |
|
|
|
color: #999; |
|
|
|
.tree-item.waypoint-item .tree-item-header { |
|
|
|
background: rgba(224, 238, 255, 0.8); |
|
|
|
} |
|
|
|
|
|
|
|
.route-actions { |
|
|
|
display: flex; |
|
|
|
gap: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.route-actions i { |
|
|
|
cursor: pointer; |
|
|
|
color: #008aff; |
|
|
|
font-size: 14px; |
|
|
|
padding: 4px; |
|
|
|
border-radius: 4px; |
|
|
|
transition: all 0.2s; |
|
|
|
} |
|
|
|
|
|
|
|
.route-actions i:hover { |
|
|
|
background: rgba(0, 138, 255, 0.1); |
|
|
|
transform: scale(1.2); |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-list { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 8px; |
|
|
|
.tree-item.active .tree-item-header { |
|
|
|
background: rgba(0, 138, 255, 0.15) !important; |
|
|
|
border-color: rgba(0, 138, 255, 0.3); |
|
|
|
box-shadow: 0 2px 10px rgba(0, 138, 255, 0.25); |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 10px; |
|
|
|
padding: 10px; |
|
|
|
background: rgba(255, 255, 255, 0.8); |
|
|
|
border-radius: 6px; |
|
|
|
transition: all 0.3s; |
|
|
|
border: 1px solid rgba(0, 138, 255, 0.1); |
|
|
|
.tree-item.selected .tree-item-header { |
|
|
|
background: rgba(0, 138, 255, 0.1) !important; |
|
|
|
border-color: rgba(0, 138, 255, 0.2); |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-item:hover { |
|
|
|
background: rgba(0, 138, 255, 0.1); |
|
|
|
transform: translateX(-2px); |
|
|
|
box-shadow: 0 2px 8px rgba(0, 138, 255, 0.15); |
|
|
|
.tree-icon { |
|
|
|
font-size: 16px; |
|
|
|
color: #008aff; |
|
|
|
flex-shrink: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-info { |
|
|
|
.tree-item-info { |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-name { |
|
|
|
.tree-item-name { |
|
|
|
font-size: 14px; |
|
|
|
font-weight: 500; |
|
|
|
color: #333; |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-meta { |
|
|
|
.tree-item-meta { |
|
|
|
font-size: 12px; |
|
|
|
color: #999; |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-actions { |
|
|
|
.tree-item-actions { |
|
|
|
display: flex; |
|
|
|
gap: 8px; |
|
|
|
flex-shrink: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-actions i { |
|
|
|
.tree-item-actions i { |
|
|
|
cursor: pointer; |
|
|
|
color: #008aff; |
|
|
|
font-size: 14px; |
|
|
|
@ -576,11 +694,27 @@ export default { |
|
|
|
transition: all 0.2s; |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-actions i:hover { |
|
|
|
.tree-item-actions i:hover { |
|
|
|
background: rgba(0, 138, 255, 0.1); |
|
|
|
transform: scale(1.2); |
|
|
|
} |
|
|
|
|
|
|
|
.tree-children { |
|
|
|
margin-left: 20px; |
|
|
|
margin-top: 4px; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.route-children { |
|
|
|
margin-left: 25px; |
|
|
|
} |
|
|
|
|
|
|
|
.waypoint-children { |
|
|
|
margin-left: 50px; |
|
|
|
} |
|
|
|
|
|
|
|
.action-buttons { |
|
|
|
display: flex; |
|
|
|
gap: 10px; |
|
|
|
@ -804,4 +938,20 @@ export default { |
|
|
|
.blue-warning { |
|
|
|
color: #e6a23c; |
|
|
|
} |
|
|
|
|
|
|
|
.platform-icon { |
|
|
|
width: 40px; |
|
|
|
height: 40px; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
overflow: hidden; /* 裁剪超出部分 */ |
|
|
|
} |
|
|
|
|
|
|
|
.platform-img { |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
object-fit: cover; /* 关键:图片自动填充不拉伸 */ |
|
|
|
border-radius: 4px; |
|
|
|
} |
|
|
|
</style> |
|
|
|
|