2026-04-15 22:41:06 +08:00
|
|
|
<template>
|
2026-04-23 09:13:02 +08:00
|
|
|
<div
|
|
|
|
|
class="control-show-panel-box"
|
2026-05-07 13:59:14 +08:00
|
|
|
v-show="statusStore.uiComponents.controlPanel.show"
|
2026-04-23 09:13:02 +08:00
|
|
|
>
|
2026-04-15 22:41:06 +08:00
|
|
|
<div class="title-box">
|
2026-05-04 21:46:36 +08:00
|
|
|
<header>图例与控制</header>
|
2026-04-15 22:41:06 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="control-show-list">
|
2026-05-04 21:46:36 +08:00
|
|
|
<!-- 按分类显示 -->
|
|
|
|
|
<div
|
|
|
|
|
v-for="(category, categoryIndex) in categorizedList"
|
|
|
|
|
:key="categoryIndex"
|
|
|
|
|
class="category-section"
|
|
|
|
|
>
|
|
|
|
|
<!-- 分类标题 -->
|
|
|
|
|
<div class="category-title">{{ category.title }}</div>
|
|
|
|
|
<!-- 分类下的项目 -->
|
|
|
|
|
<div
|
|
|
|
|
v-for="(item, index) in category.items"
|
|
|
|
|
:key="index"
|
|
|
|
|
class="control-item"
|
|
|
|
|
>
|
|
|
|
|
<el-checkbox
|
|
|
|
|
v-model="item.statusStore[item.statusKey].show"
|
|
|
|
|
@change="
|
|
|
|
|
changeStatus(item.statusStore[item.statusKey].show, item.callback)
|
|
|
|
|
"
|
|
|
|
|
/>
|
|
|
|
|
<!-- 图例部分 -->
|
|
|
|
|
<div class="legend-content">
|
|
|
|
|
<!-- 支持图片链接 -->
|
|
|
|
|
<img
|
|
|
|
|
v-if="item.link"
|
|
|
|
|
:src="item.link"
|
|
|
|
|
:alt="item.name"
|
|
|
|
|
class="legend-item-img"
|
|
|
|
|
/>
|
|
|
|
|
<!-- 支持HTML+CSS样式 -->
|
|
|
|
|
<div
|
|
|
|
|
v-else-if="item.html"
|
|
|
|
|
v-html="item.html"
|
|
|
|
|
class="legend-item-html"
|
|
|
|
|
></div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 描述文字 -->
|
2026-05-04 22:29:53 +08:00
|
|
|
<span class="item-description">
|
|
|
|
|
{{ item.name }}
|
|
|
|
|
<span
|
|
|
|
|
v-if="item.count && item.count() !== null"
|
|
|
|
|
class="point-count"
|
|
|
|
|
>
|
|
|
|
|
({{ item.count() }})
|
|
|
|
|
</span>
|
|
|
|
|
</span>
|
2026-05-04 21:46:36 +08:00
|
|
|
</div>
|
2026-04-15 22:41:06 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
2026-04-21 19:50:57 +08:00
|
|
|
import { useLoadingInformationStore } from '@/stores/useLoadingInformation.ts';
|
2026-04-23 09:13:02 +08:00
|
|
|
import { useStatusStore } from '@/stores/useStatusStore';
|
2026-05-04 21:46:36 +08:00
|
|
|
import { computed } from 'vue';
|
2026-04-18 19:44:28 +08:00
|
|
|
|
2026-05-07 13:59:14 +08:00
|
|
|
const statusStore = useStatusStore();
|
|
|
|
|
const loadingInformationStore = useLoadingInformationStore();
|
2026-05-07 12:53:25 +08:00
|
|
|
|
2026-05-04 21:46:36 +08:00
|
|
|
const props = defineProps<{
|
2026-04-15 22:41:06 +08:00
|
|
|
constrolShowList: {
|
|
|
|
|
name: string;
|
2026-04-18 16:40:04 +08:00
|
|
|
statusStore: Record<string, { show: boolean; loading: boolean }>;
|
|
|
|
|
statusKey: string;
|
2026-04-15 22:41:06 +08:00
|
|
|
callback: (...args: unknown[]) => unknown;
|
2026-05-04 21:46:36 +08:00
|
|
|
link?: string; // 图例图片链接
|
|
|
|
|
html?: string; // 图例HTML内容
|
|
|
|
|
category?: string; // 分类名称
|
2026-05-04 22:29:53 +08:00
|
|
|
count?: () => number | null; // 获取点数量的函数
|
2026-04-15 22:41:06 +08:00
|
|
|
}[];
|
|
|
|
|
}>();
|
2026-04-18 19:44:28 +08:00
|
|
|
|
2026-05-04 21:46:36 +08:00
|
|
|
// 按分类组织的数据
|
|
|
|
|
const categorizedList = computed(() => {
|
|
|
|
|
const categories: Record<
|
|
|
|
|
string,
|
|
|
|
|
{ title: string; items: typeof props.constrolShowList }
|
|
|
|
|
> = {};
|
|
|
|
|
|
|
|
|
|
props.constrolShowList.forEach((item) => {
|
|
|
|
|
const categoryName = item.category || '其他';
|
|
|
|
|
if (!categories[categoryName]) {
|
|
|
|
|
categories[categoryName] = {
|
|
|
|
|
title: categoryName,
|
|
|
|
|
items: [],
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
categories[categoryName].items.push(item);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Object.values(categories);
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-18 19:44:28 +08:00
|
|
|
// 状态改变执行
|
|
|
|
|
const changeStatus = (
|
|
|
|
|
status: boolean,
|
|
|
|
|
callback: (...args: unknown[]) => unknown
|
|
|
|
|
) => {
|
|
|
|
|
// 重置信息框状态,隐藏显示
|
2026-05-07 13:59:14 +08:00
|
|
|
loadingInformationStore.resetStatue();
|
2026-04-18 19:44:28 +08:00
|
|
|
|
|
|
|
|
// 调用回调函数
|
|
|
|
|
callback(status);
|
|
|
|
|
};
|
2026-04-15 22:41:06 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.control-show-panel-box {
|
|
|
|
|
position: absolute;
|
2026-05-04 21:46:36 +08:00
|
|
|
bottom: 20px;
|
|
|
|
|
right: 20px;
|
2026-04-15 22:41:06 +08:00
|
|
|
border-radius: 2px;
|
|
|
|
|
z-index: 1000;
|
2026-05-04 22:29:53 +08:00
|
|
|
width: 200px;
|
2026-05-04 22:05:03 +08:00
|
|
|
overflow: hidden;
|
2026-04-15 22:41:06 +08:00
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
|
|
color: white;
|
|
|
|
|
border: 1px solid rgb(0, 225, 255);
|
2026-05-04 22:05:03 +08:00
|
|
|
max-height: 50vh;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
2026-04-15 22:41:06 +08:00
|
|
|
}
|
|
|
|
|
.title-box {
|
|
|
|
|
font-weight: bold;
|
2026-05-04 22:05:03 +08:00
|
|
|
font-size: 14px;
|
2026-04-15 22:41:06 +08:00
|
|
|
background: linear-gradient(
|
|
|
|
|
180deg,
|
|
|
|
|
rgb(86, 204, 242) 0%,
|
|
|
|
|
rgb(47, 128, 237) 100%
|
|
|
|
|
);
|
|
|
|
|
padding: 8px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
.control-show-list {
|
|
|
|
|
background: rgba(14, 52, 98, 0.8);
|
|
|
|
|
padding: 8px;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
2026-05-04 22:05:03 +08:00
|
|
|
font-size: 12px;
|
2026-04-15 22:41:06 +08:00
|
|
|
gap: 6px;
|
2026-05-04 21:46:36 +08:00
|
|
|
overflow-y: auto;
|
2026-05-04 22:05:03 +08:00
|
|
|
overflow-x: hidden;
|
|
|
|
|
flex: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 自定义滚动条样式 */
|
|
|
|
|
.control-show-list::-webkit-scrollbar {
|
|
|
|
|
width: 6px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.control-show-list::-webkit-scrollbar-track {
|
|
|
|
|
background: rgba(14, 52, 98, 0.5);
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.control-show-list::-webkit-scrollbar-thumb {
|
|
|
|
|
background: linear-gradient(
|
|
|
|
|
180deg,
|
|
|
|
|
rgba(86, 204, 242, 0.8) 0%,
|
|
|
|
|
rgba(47, 128, 237, 0.8) 100%
|
|
|
|
|
);
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
transition: background 0.3s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.control-show-list::-webkit-scrollbar-thumb:hover {
|
|
|
|
|
background: linear-gradient(
|
|
|
|
|
180deg,
|
|
|
|
|
rgba(86, 204, 242, 1) 0%,
|
|
|
|
|
rgba(47, 128, 237, 1) 100%
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Firefox 滚动条样式 */
|
|
|
|
|
.control-show-list {
|
|
|
|
|
scrollbar-width: thin;
|
|
|
|
|
scrollbar-color: rgba(86, 204, 242, 0.8) rgba(14, 52, 98, 0.5);
|
2026-05-04 21:46:36 +08:00
|
|
|
}
|
|
|
|
|
.category-section {
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
}
|
|
|
|
|
.category-title {
|
|
|
|
|
font-weight: bold;
|
2026-05-04 22:05:03 +08:00
|
|
|
font-size: 12px;
|
2026-05-04 21:46:36 +08:00
|
|
|
color: #00e1ff;
|
|
|
|
|
padding: 4px 0;
|
|
|
|
|
margin-bottom: 4px;
|
|
|
|
|
border-bottom: 1px solid rgba(0, 225, 255, 0.3);
|
|
|
|
|
}
|
|
|
|
|
.control-item {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
padding: 2px 0;
|
|
|
|
|
}
|
|
|
|
|
.legend-content {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
min-width: 20px;
|
|
|
|
|
}
|
|
|
|
|
.legend-item-img {
|
|
|
|
|
width: 18px;
|
|
|
|
|
height: 18px;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
object-fit: contain;
|
|
|
|
|
}
|
|
|
|
|
.legend-item-html {
|
|
|
|
|
width: 18px;
|
|
|
|
|
height: 18px;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
.legend-item-html :deep(*) {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
.item-description {
|
|
|
|
|
flex: 1;
|
|
|
|
|
text-align: justify;
|
|
|
|
|
text-justify: inter-ideograph;
|
2026-05-04 22:05:03 +08:00
|
|
|
font-size: 12px;
|
2026-05-04 21:46:36 +08:00
|
|
|
line-height: 1.5;
|
|
|
|
|
letter-spacing: 0.5px;
|
|
|
|
|
word-break: break-all;
|
2026-05-04 22:29:53 +08:00
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 4px;
|
|
|
|
|
}
|
|
|
|
|
.point-count {
|
|
|
|
|
color: #00e1ff;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
white-space: nowrap;
|
2026-04-15 22:41:06 +08:00
|
|
|
}
|
|
|
|
|
:deep(.el-checkbox) {
|
|
|
|
|
height: auto;
|
|
|
|
|
color: #fff;
|
2026-05-04 21:46:36 +08:00
|
|
|
margin-right: 0;
|
2026-04-15 22:41:06 +08:00
|
|
|
}
|
2026-04-16 09:32:33 +08:00
|
|
|
:deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
|
|
|
|
|
color: #fff;
|
|
|
|
|
}
|
2026-04-15 22:41:06 +08:00
|
|
|
</style>
|