2025-08-25 20:27:25 +08:00
|
|
|
|
<template>
|
|
|
|
|
<div class="go-iframe-container" :style="{ width: w + 'px', height: h + 'px' }">
|
2025-09-05 17:11:30 +08:00
|
|
|
|
<!-- 按钮容器,绝对定位在右上角 -->
|
2025-08-28 17:12:22 +08:00
|
|
|
|
<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>
|
|
|
|
|
|
2025-08-27 10:01:26 +08:00
|
|
|
|
<iframe ref="iframeRef" class="iframe-content" src="/static/index.html"></iframe>
|
2025-08-25 20:27:25 +08:00
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2025-08-28 17:12:22 +08:00
|
|
|
|
import axios from 'axios';
|
2025-08-25 20:27:25 +08:00
|
|
|
|
import config, { BarOption } from './config';
|
2025-08-28 17:12:22 +08:00
|
|
|
|
import { PropType, toRefs, ref, onMounted, computed, watch } from 'vue';
|
2025-08-25 20:27:25 +08:00
|
|
|
|
import dataJson from './data.json'
|
2025-09-02 14:24:21 +08:00
|
|
|
|
import axiosInstance from '@/api/axios';
|
2025-08-25 20:27:25 +08:00
|
|
|
|
|
|
|
|
|
const iframeRef = ref<HTMLIFrameElement | null>(null);
|
|
|
|
|
const isIframeReady = ref(false); // 2. 创建一个状态来跟踪 iframe 是否已加载
|
|
|
|
|
let iframeApi: any = null;
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
chartConfig: {
|
|
|
|
|
type: Object as PropType<config>,
|
|
|
|
|
required: true
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const { w, h } = toRefs(props.chartConfig.attr)
|
|
|
|
|
|
2025-08-28 17:12:22 +08:00
|
|
|
|
const buttons = ref([
|
|
|
|
|
{ id: 1, label: '场所分布情况' },
|
|
|
|
|
{ id: 2, label: '当日作业情况' }
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const activeButtonId = ref(buttons.value[0].id);
|
2025-08-25 20:27:25 +08:00
|
|
|
|
|
2025-08-28 17:12:22 +08:00
|
|
|
|
// 按钮点击事件
|
|
|
|
|
const selectButton = (id: number) => {
|
|
|
|
|
activeButtonId.value = id; // 更新激活状态的 ID
|
|
|
|
|
console.log(`按钮 ${id} 被选中`);
|
|
|
|
|
updateChartData(id);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据按钮ID更新图表数据
|
|
|
|
|
* @param buttonId 当前激活的按钮ID
|
|
|
|
|
*/
|
|
|
|
|
const updateChartData = async (buttonId: number) => {
|
2025-09-03 14:50:26 +08:00
|
|
|
|
let dataToRender: any = [];
|
2025-08-28 17:12:22 +08:00
|
|
|
|
if (buttonId === 1) {
|
2025-08-28 19:45:19 +08:00
|
|
|
|
dataToRender = await fetchData('/spaceMapMock');
|
2025-08-28 17:12:22 +08:00
|
|
|
|
} else if (buttonId === 2) {
|
2025-08-28 19:45:19 +08:00
|
|
|
|
dataToRender = await fetchData('/dayMapMock');
|
2025-08-28 17:12:22 +08:00
|
|
|
|
} else {
|
2025-09-03 14:50:26 +08:00
|
|
|
|
console.warn(`未知的按钮ID: ${buttonId}`);
|
2025-08-28 17:12:22 +08:00
|
|
|
|
}
|
|
|
|
|
props.chartConfig.option.dataset.barOptions = dataToRender;
|
|
|
|
|
console.log(`已为按钮 ${buttonId} 加载 ${dataToRender.length} 条数据。`);
|
|
|
|
|
};
|
|
|
|
|
const fetchData = async (url: string) => {
|
2025-08-28 19:45:19 +08:00
|
|
|
|
if (url == '/spaceMapMock') {
|
|
|
|
|
return dataJson.barOptions;
|
2025-09-03 14:50:26 +08:00
|
|
|
|
} else {
|
2025-08-28 19:45:19 +08:00
|
|
|
|
return [{ "location": "四川省.成都市", "items": [{ "tall": 120, "color": "#ff4757" }, { "tall": 50, "color": "#3A86FF" }] }, { "location": "广东省.深圳市", "items": [{ "tall": 90, "color": "#5352ed" }, { "tall": 40, "color": "#5352ed" }] }, { "location": "浙江省.杭州市", "items": [{ "tall": 150, "color": "#ff4757" }, { "tall": 70, "color": "#4ECDC4" }] }, { "location": "江苏省.南京市", "items": [{ "tall": 100, "color": "#ff4757" }, { "tall": 45, "color": "#FFD166" }] }, { "location": "湖北省.武汉市", "items": [{ "tall": 110, "color": "#ff4757" }, { "tall": 52, "color": "#6A0572" }] }, { "location": "陕西省.西安市", "items": [{ "tall": 85, "color": "#ff4757" }, { "tall": 38, "color": "#1A535C" }] }, { "location": "山东省.青岛市", "items": [{ "tall": 130, "color": "#ff4757" }, { "tall": 60, "color": "#FF8C42" }] }, { "location": "河南省.郑州市", "items": [{ "tall": 95, "color": "#ff4757" }, { "tall": 43, "color": "#7209B7" }] }, { "location": "福建省.厦门市", "items": [{ "tall": 140, "color": "#ff4757" }, { "tall": 65, "color": "#06D6A0" }] }, { "location": "辽宁省.大连市", "items": [{ "tall": 88, "color": "#ff4757" }, { "tall": 41, "color": "#118AB2" }] }]
|
|
|
|
|
}
|
2025-09-03 14:50:26 +08:00
|
|
|
|
// try {
|
|
|
|
|
// // 无后端接口, 此为预留
|
|
|
|
|
// const response: any = await axiosInstance.get(`/dev${url}`, { baseURL: '' });
|
|
|
|
|
// if (response.state === true && response.value && response.value.length > 0) {
|
|
|
|
|
// return response.value; // 返回原始数据
|
|
|
|
|
// } else {
|
|
|
|
|
// console.warn('API调用失败或返回空数据,将使用静态数据。');
|
|
|
|
|
// return dataJson.barOptions;
|
|
|
|
|
// }
|
|
|
|
|
// } catch (error) {
|
|
|
|
|
// console.error('获取图表数据失败将使用静态数据:', error);
|
|
|
|
|
// return dataJson.barOptions;
|
|
|
|
|
// }
|
2025-08-28 17:12:22 +08:00
|
|
|
|
};
|
2025-08-25 20:27:25 +08:00
|
|
|
|
const BarOptionsData = computed(() => {
|
2025-08-28 17:12:22 +08:00
|
|
|
|
return props.chartConfig.option.dataset.barOptions.map((item: unknown) =>
|
2025-08-25 20:27:25 +08:00
|
|
|
|
new BarOption(item as unknown as Partial<BarOption>)
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
const iframe = iframeRef.value;
|
|
|
|
|
if (iframe) {
|
2025-08-28 17:12:22 +08:00
|
|
|
|
iframe.onload = async () => {
|
2025-08-25 20:27:25 +08:00
|
|
|
|
console.log(" Iframe content has loaded!");
|
|
|
|
|
if (iframe.contentWindow && (iframe.contentWindow as any).g) {
|
|
|
|
|
iframeApi = (iframe.contentWindow as any).g.active3d;
|
|
|
|
|
isIframeReady.value = true;
|
2025-08-28 17:12:22 +08:00
|
|
|
|
|
2025-09-03 14:50:26 +08:00
|
|
|
|
const data = await fetchData('/spaceMapMock');
|
2025-08-28 17:12:22 +08:00
|
|
|
|
props.chartConfig.option.dataset.barOptions = data;
|
|
|
|
|
|
2025-08-25 20:27:25 +08:00
|
|
|
|
} else {
|
|
|
|
|
console.error("无法访问 iframe 内的 g.active3d 对象。");
|
|
|
|
|
}
|
2025-08-28 17:12:22 +08:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
BarOptionsData.value.forEach((barConfig: any) => {
|
|
|
|
|
callIframeMethod("setProvinceFocusable", false)
|
2025-08-28 18:56:34 +08:00
|
|
|
|
// console.log(" Drawing bar with config:", barConfig);
|
2025-08-28 17:12:22 +08:00
|
|
|
|
callIframeMethod("createBar", barConfig);
|
|
|
|
|
});
|
|
|
|
|
}, 500); // 500ms延迟,可根据实际情况调整
|
2025-08-25 20:27:25 +08:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-08-28 17:12:22 +08:00
|
|
|
|
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);
|
2025-08-25 20:27:25 +08:00
|
|
|
|
setTimeout(() => {
|
2025-08-28 17:12:22 +08:00
|
|
|
|
callIframeMethod("clearAllBars");
|
|
|
|
|
newBarOptionsData.forEach((barConfig: BarOption) => {
|
|
|
|
|
console.log(" Re-drawing bar with config:", barConfig);
|
2025-08-25 20:27:25 +08:00
|
|
|
|
callIframeMethod("createBar", barConfig);
|
|
|
|
|
});
|
2025-08-28 17:12:22 +08:00
|
|
|
|
}, 500);
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
immediate: true,
|
|
|
|
|
deep: false
|
2025-08-25 20:27:25 +08:00
|
|
|
|
}
|
2025-08-28 17:12:22 +08:00
|
|
|
|
);
|
2025-08-25 20:27:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 调用 iframe 内部方法的通用函数
|
|
|
|
|
*/
|
|
|
|
|
function callIframeMethod(methodName: string, ...args: any[]) {
|
|
|
|
|
if (iframeApi && typeof iframeApi[methodName] === 'function') {
|
|
|
|
|
iframeApi[methodName].apply(iframeApi, args);
|
|
|
|
|
} else if (isIframeReady.value) {
|
|
|
|
|
console.error(`方法 ${methodName} 在 iframe API 上不存在。`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.go-iframe-container {
|
|
|
|
|
overflow: hidden;
|
2025-08-28 17:12:22 +08:00
|
|
|
|
position: relative; // 为内部的绝对定位元素提供定位上下文
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.button-container-wrapper {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 20px;
|
2025-09-05 17:11:30 +08:00
|
|
|
|
right: 20px;
|
2025-08-28 17:12:22 +08:00
|
|
|
|
z-index: 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.button-container {
|
|
|
|
|
display: flex;
|
2025-09-05 17:11:30 +08:00
|
|
|
|
flex-direction: row;
|
|
|
|
|
// gap: 10px;
|
|
|
|
|
// width: 400px;
|
|
|
|
|
height: 50px;
|
2025-08-28 17:12:22 +08:00
|
|
|
|
padding: 0;
|
2025-09-05 17:11:30 +08:00
|
|
|
|
|
|
|
|
|
|
2025-08-28 17:12:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.button {
|
|
|
|
|
position: relative;
|
2025-09-05 17:11:30 +08:00
|
|
|
|
margin: 1px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
padding: 12px 0px;
|
|
|
|
|
width: 200px;
|
|
|
|
|
font-size: 14px;
|
2025-08-28 17:12:22 +08:00
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
/* 平滑过渡效果 */
|
|
|
|
|
overflow: hidden;
|
2025-09-05 17:11:30 +08:00
|
|
|
|
background-image: url('./assets/unselect.png');
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
color: rgb(193, 193, 193);
|
|
|
|
|
// background-color: bisque;
|
2025-08-28 17:12:22 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 激活状态的样式 */
|
|
|
|
|
.button.active {
|
2025-09-05 17:11:30 +08:00
|
|
|
|
background-image: url('./assets/selected.png');
|
|
|
|
|
color: #eee;
|
2025-08-28 17:12:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 非激活状态按钮的悬停效果 */
|
|
|
|
|
.button:not(.active):hover {
|
|
|
|
|
filter: brightness(1.1);
|
2025-08-25 20:27:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.iframe-content {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
border: none;
|
|
|
|
|
}
|
2025-09-05 17:11:30 +08:00
|
|
|
|
|
|
|
|
|
.button:nth-child(1) {
|
|
|
|
|
transform: translateX(30px); // 将第二个按钮向左移动
|
|
|
|
|
}
|
|
|
|
|
</style>
|