feat: 按钮

This commit is contained in:
Free-sss 2025-08-28 17:12:22 +08:00
parent 5cf56739c0
commit 2842fdd0ac
4 changed files with 219 additions and 30 deletions

View File

@ -118,7 +118,7 @@ export class BarOption {
const finalColor = item.color ?? defaultColorSet.color;
const finalWfColor = item.wfColor ?? defaultColorSet.wfColor;
console.log(`Location: ${opts.location || 'Unknown'}, Item index: ${index}, Final color: ${finalColor}`);
// 3. 创建一个新的 BarItem 实例,包含所有信息
return new BarItem({
...item,

View File

@ -1,13 +1,25 @@
<template>
<div class="go-iframe-container" :style="{ width: w + 'px', height: h + 'px' }">
<!-- 按钮容器绝对定位在左上角 -->
<div class="button-container-wrapper">
<div class="button-container">
<div v-for="btn in buttons" :key="btn.id" :class="['button', { active: btn.id === activeButtonId }]"
@click="selectButton(btn.id)">
<span>{{ btn.label }}</span>
</div>
</div>
</div>
<iframe ref="iframeRef" class="iframe-content" src="/static/index.html"></iframe>
</div>
</template>
<script setup lang="ts">
import axios from 'axios';
import config, { BarOption } from './config';
import { PropType, toRefs, ref, onMounted, computed, watchEffect } from 'vue'; // 1. watchEffect
import { PropType, toRefs, ref, onMounted, computed, watch } from 'vue';
import dataJson from './data.json'
import { option } from 'keymaster';
const iframeRef = ref<HTMLIFrameElement | null>(null);
const isIframeReady = ref(false); // 2. iframe
@ -22,52 +34,105 @@ const props = defineProps({
const { w, h } = toRefs(props.chartConfig.attr)
const buttons = ref([
{ id: 1, label: '场所分布情况' },
{ id: 2, label: '当日作业情况' }
]);
const activeButtonId = ref(buttons.value[0].id);
//
const selectButton = (id: number) => {
activeButtonId.value = id; // ID
console.log(`按钮 ${id} 被选中`);
updateChartData(id);
};
/**
* 根据按钮ID更新图表数据
* @param buttonId 当前激活的按钮ID
*/
const updateChartData = async (buttonId: number) => {
let dataToRender: BarOption[] = [];
if (buttonId === 1) {
dataToRender = await fetchData('/space');
} else if (buttonId === 2) {
dataToRender = await fetchData('/day');
} else {
console.warn(`未知的按钮ID: ${buttonId},将使用默认数据。`);
}
// chartConfig BarOptionsData computed watch
props.chartConfig.option.dataset.barOptions = dataToRender;
console.log(`已为按钮 ${buttonId} 加载 ${dataToRender.length} 条数据。`);
};
const fetchData = async (url: string) => {
try {
const response = await axios.get(url);
if (response.data.state === true && response.data.value && response.data.value.length > 0) {
return response.data.value; //
} else {
console.warn('API调用失败或返回空数据将使用静态数据。');
return dataJson.barOptions;
}
} catch (error) {
console.error('获取图表数据失败将使用静态数据:', error);
return dataJson.barOptions;
}
};
const BarOptionsData = computed(() => {
return dataJson.barOptions.map(item =>
return props.chartConfig.option.dataset.barOptions.map((item: unknown) =>
new BarOption(item as unknown as Partial<BarOption>)
);
});
console.log(BarOptionsData)
onMounted(() => {
const iframe = iframeRef.value;
if (iframe) {
iframe.onload = () => {
iframe.onload = async () => {
console.log(" Iframe content has loaded!");
if (iframe.contentWindow && (iframe.contentWindow as any).g) {
iframeApi = (iframe.contentWindow as any).g.active3d;
isIframeReady.value = true;
const data = await fetchData('/map');
props.chartConfig.option.dataset.barOptions = data;
} else {
console.error("无法访问 iframe 内的 g.active3d 对象。");
}
};
//
setTimeout(() => {
BarOptionsData.value.forEach((barConfig: any) => {
callIframeMethod("setProvinceFocusable", false)
}, 3000)
}
});
// 4. 使 watchEffect
// index.vue
watchEffect(() => {
if (isIframeReady.value && BarOptionsData.value && iframeApi) {
// console.log(" Drawing chart with new options...");
// iframe
setTimeout(() => {
BarOptionsData.value.forEach(barConfig => {
// console.log(" Drawing bar with config:", barConfig);
console.log(" Drawing bar with config:", barConfig);
callIframeMethod("createBar", barConfig);
});
}, 500); // 500ms
};
}
});
watch(
BarOptionsData,
(newBarOptionsData) => {
if (!isIframeReady.value) {
console.warn("Iframe API not ready, skipping bar rendering in watch.");
return;
}
console.log("Watch triggered with newBarOptionsData:", newBarOptionsData);
setTimeout(() => {
callIframeMethod("clearAllBars");
newBarOptionsData.forEach((barConfig: BarOption) => {
console.log(" Re-drawing bar with config:", barConfig);
callIframeMethod("createBar", barConfig);
});
}, 500);
},
{
immediate: true,
deep: false
}
);
/**
* 调用 iframe 内部方法的通用函数
@ -83,10 +148,130 @@ function callIframeMethod(methodName: string, ...args: any[]) {
<style lang="scss" scoped>
.go-iframe-container {
// width: 1300px;
// height: 900px;
overflow: hidden;
// border: 1px solid #ccc;
position: relative; //
--inactive-border-color: #337ab7;
--inactive-text-color: #a0c0e0;
--inactive-bg-color: rgba(10, 25, 40, 0.7);
--active-border-color: #f7b731;
--active-text-color: #f7b731;
--active-text-shadow: 0 0 8px rgba(247, 183, 49, 0.7);
/* 边框L型括号的尺寸参数 */
--bracket-thickness: 3px;
/* 括号线条粗细 */
--bracket-arm-length: 8px;
/* 括号横向臂长 */
--vertical-segment-height: 8px;
/* 括号垂直部分顶部和底部的长度,中间留空 */
}
.button-container-wrapper {
position: absolute;
top: 20px;
left: 20px;
z-index: 10;
}
.button-container {
display: flex;
flex-direction: column;
gap: 10px;
width: fit-content;
padding: 0;
border-radius: 5px;
}
.button {
position: relative;
padding: 12px 30px;
font-size: 1.1em;
font-weight: bold;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
/* 平滑过渡效果 */
overflow: hidden;
--_current-border-color: var(--inactive-border-color);
--_current-text-color: var(--inactive-text-color);
--_current-text-shadow: none;
background-color: var(--inactive-bg-color);
/* 按钮背景色 */
color: var(--_current-text-color);
text-shadow: var(--_current-text-shadow);
/* 按钮本体的细线边框:顶部、底部、右侧 */
border-top: 1px solid var(--_current-border-color);
border-bottom: 1px solid var(--_current-border-color);
border-right: 1px solid var(--_current-border-color);
border-left: none;
/* 左侧边框由伪元素绘制 */
}
/* 激活状态的样式 */
.button.active {
--_current-border-color: var(--active-border-color);
--_current-text-color: var(--active-text-color);
--_current-text-shadow: var(--active-text-shadow);
color: var(--_current-text-color);
text-shadow: var(--_current-text-shadow);
border-top-color: var(--_current-border-color);
border-bottom-color: var(--_current-border-color);
border-right-color: var(--_current-border-color);
}
.button::before {
content: '';
position: absolute;
top: -1px;
left: -1px;
width: var(--bracket-arm-length);
height: calc(100% + 2px);
border-color: var(--_current-border-color);
border-style: solid;
/* border-width: top right bottom left */
border-width: var(--bracket-thickness) 0 var(--bracket-thickness) var(--bracket-thickness);
/* 使用线性渐变背景来创建左侧垂直部分的断开效果 */
background: linear-gradient(to bottom,
var(--_current-border-color) 0%,
var(--_current-border-color) var(--vertical-segment-height),
transparent var(--vertical-segment-height),
transparent calc(100% - var(--vertical-segment-height)),
var(--_current-border-color) calc(100% - var(--vertical-segment-height)),
var(--_current-border-color) 100%) no-repeat left center / var(--bracket-thickness) 100%;
transition: border-color 0.3s ease, background 0.3s ease;
/* 过渡颜色变化 */
}
.button::after {
content: '';
position: absolute;
top: -1px;
right: -1px;
/* 向右偏移1px与父元素的右边缘对齐 */
width: var(--bracket-arm-length);
height: calc(100% + 2px);
border-color: var(--_current-border-color);
border-style: solid;
/* 伪元素的边框用于绘制 L 型括号的水平部分和右侧垂直部分的厚度 */
/* border-width: top right bottom left */
border-width: var(--bracket-thickness) var(--bracket-thickness) var(--bracket-thickness) 0;
/* 使用线性渐变背景来创建右侧垂直部分的断开效果 */
background: linear-gradient(to bottom,
var(--_current-border-color) 0%,
var(--_current-border-color) var(--vertical-segment-height),
transparent var(--vertical-segment-height),
transparent calc(100% - var(--vertical-segment-height)),
var(--_current-border-color) calc(100% - var(--vertical-segment-height)),
var(--_current-border-color) 100%) no-repeat right center / var(--bracket-thickness) 100%;
transition: border-color 0.3s ease, background 0.3s ease;
}
/* 非激活状态按钮的悬停效果 */
.button:not(.active):hover {
filter: brightness(1.1);
/* 略微提高亮度 */
}
.iframe-content {

View File

@ -3,7 +3,7 @@
"message": "Success",
"value": [
{
"label": "中国中车集团有限公司",
"label": "中国中车集团有限公司sss",
"key": "1674696717063430144",
"grade": "org",
"parentId": "0",

View File

@ -536,8 +536,8 @@ const fetchCameraTree = async () => {
return [];
}
} catch (error) {
console.error('获取摄像头树失败:', error);
return [];
console.error('获取摄像头树失败使用静态数据:', error);
return props.chartConfig.option.dataset.list;
}
};
onMounted(async () => {
@ -616,6 +616,10 @@ const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (n
background-image: url('data:image/png;base64,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');
}
.title_text {
padding-left: 10px;
}
.button {
background-color: #1E5676;
border: 1px solid #2E6E89;