229 lines
5.9 KiB
Vue
229 lines
5.9 KiB
Vue
<script setup>
|
|
import { useRoute } from "vue-router";
|
|
import EffectScatter from "@/components/chart/EffectScatter.vue";
|
|
import { computed, inject, nextTick, ref, watch } from "vue";
|
|
import { twMerge } from "tailwind-merge";
|
|
import useSelectedFloor from "@/hooks/useSelectedFloor";
|
|
|
|
const route = useRoute();
|
|
|
|
const { currentFloor, subscribeData, realtimeData } = inject("system_deviceList");
|
|
const { getCurrentInfoModalData, selected_dbid } = inject(
|
|
"system_selectedDevice"
|
|
);
|
|
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
|
|
|
const asset_floor_chart = ref(null);
|
|
const sameOption = {
|
|
type: "effectScatter",
|
|
coordinateSystem: "geo",
|
|
geoIndex: 0,
|
|
encode: {
|
|
tooltip: 2,
|
|
},
|
|
};
|
|
|
|
// 根據設備取得即時狀態顏色
|
|
const getDeviceRealtimeColor = (device) => {
|
|
if (device.full_name === 'SmartSocket-AA001') return 'red';
|
|
if (device.full_name === 'SmartSocket-AA003' || device.full_name === 'SmartSocket-AA004') return 'gray';
|
|
const realtimeDevice = realtimeData.value?.find(
|
|
(item) => item.device_number === device.device_number
|
|
);
|
|
const state = realtimeDevice?.state || '';
|
|
if (state === 'offnormal' || state === '') return device.device_close_color || '#999';
|
|
return device.device_normal_color || '#009100';
|
|
};
|
|
|
|
const defaultOption = (map, data = []) => {
|
|
return {
|
|
animation: false,
|
|
tooltip: {},
|
|
geo: {
|
|
tooltip: {
|
|
show: false,
|
|
},
|
|
map,
|
|
roam: true, // 一定要关闭拖拽
|
|
},
|
|
series: [
|
|
{
|
|
...sameOption,
|
|
symbolSize: 10,
|
|
itemStyle: {
|
|
color: (params) => getDeviceRealtimeColor(params.data[2]),
|
|
},
|
|
data,
|
|
},
|
|
{
|
|
...sameOption,
|
|
symbolSize: 20,
|
|
itemStyle: {
|
|
color: (params) => getDeviceRealtimeColor(params.data[2]),
|
|
},
|
|
data: [],
|
|
},
|
|
],
|
|
};
|
|
};
|
|
// 監聽 realtimeData 變化,刷新地圖顏色
|
|
watch(
|
|
realtimeData,
|
|
() => {
|
|
setTimeout(() => {
|
|
if (
|
|
selectedFloor.value &&
|
|
asset_floor_chart.value &&
|
|
asset_floor_chart.value.chart &&
|
|
asset_floor_chart.value.chart.isDisposed() === false
|
|
) {
|
|
asset_floor_chart.value.chart.setOption(
|
|
defaultOption(selectedFloor.value?.title, selectedData.value),
|
|
true
|
|
);
|
|
}
|
|
}, 0);
|
|
},
|
|
{ deep: true }
|
|
);
|
|
|
|
const { selectedFloor } = useSelectedFloor();
|
|
|
|
const allData = ref([]);
|
|
const selectedData = ref([]);
|
|
watch(
|
|
[selectedFloor, () => asset_floor_chart],
|
|
([newValue, newChart], [oldValue]) => {
|
|
if (
|
|
newValue &&
|
|
newChart.value &&
|
|
oldValue?.key !== newValue.key &&
|
|
newValue.map_url
|
|
) {
|
|
selectedData.value =
|
|
subscribeData.value
|
|
?.filter(
|
|
(d) => d.device_coordinate && d.floor_guid === route.params.floor_id
|
|
)
|
|
.map((d) => [...d.device_coordinate.slice(1, -1).split(","), d]) ||
|
|
[];
|
|
|
|
asset_floor_chart.value.updateSvg(
|
|
{
|
|
full_name: newValue?.title,
|
|
path: `${FILE_BASEURL}/${newValue.map_url}`,
|
|
},
|
|
|
|
defaultOption(newValue?.title, selectedData.value)
|
|
);
|
|
|
|
newChart.value.chart.on("click", function (params) {
|
|
getCurrentInfoModalData(
|
|
params.event,
|
|
{
|
|
left: params.event.offsetX,
|
|
top: params.event.offsetY,
|
|
},
|
|
params.data[2]
|
|
);
|
|
selected_dbid.value[1] = params.data[2].spriteDbId;
|
|
});
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
deep: true,
|
|
}
|
|
);
|
|
|
|
watch(
|
|
subscribeData,
|
|
(newData) => {
|
|
let values = newData
|
|
?.filter(
|
|
(d) => d.device_coordinate && d.floor_guid === route.params.floor_id
|
|
)
|
|
.map((d) => [...d.device_coordinate.slice(1, -1).split(","), d]);
|
|
allData.value = values;
|
|
selectedData.value = newData
|
|
?.filter((d) => d.device_coordinate)
|
|
.map((d) => [...d.device_coordinate.slice(1, -1).split(","), d]);
|
|
if (
|
|
selectedFloor.value &&
|
|
asset_floor_chart.value &&
|
|
asset_floor_chart.value.chart &&
|
|
asset_floor_chart.value.chart.isDisposed() === false
|
|
) {
|
|
const selected = allData.value.filter((d) => d[2].is2DActive);
|
|
const unSelected = allData.value.filter((d) => !d[2].is2DActive);
|
|
setTimeout(() => {
|
|
if (asset_floor_chart.value?.chart && !asset_floor_chart.value.chart.isDisposed()) {
|
|
asset_floor_chart.value.chart.setOption({
|
|
series: [
|
|
{ data: unSelected },
|
|
{
|
|
data: selected,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}, 0);
|
|
}
|
|
},
|
|
{
|
|
deep: true,
|
|
}
|
|
);
|
|
|
|
watch(
|
|
selected_dbid,
|
|
(newSelectedDbid) => {
|
|
if (
|
|
asset_floor_chart.value &&
|
|
asset_floor_chart.value.chart &&
|
|
allData.value
|
|
) {
|
|
selectedData.value = selectedData.value.map((item) => {
|
|
if (item[2].spriteDbId === newSelectedDbid[1]) {
|
|
return [...item.slice(0, 2), { ...item[2], is2DActive: true }];
|
|
}
|
|
return [...item.slice(0, 2), { ...item[2], is2DActive: false }];
|
|
});
|
|
|
|
const selected = selectedData.value.filter((d) => d[2].is2DActive);
|
|
const unSelected = selectedData.value.filter((d) => !d[2].is2DActive);
|
|
|
|
console.log("allData.value", allData.value, selected, unSelected);
|
|
setTimeout(() => {
|
|
if (asset_floor_chart.value?.chart && !asset_floor_chart.value.chart.isDisposed()) {
|
|
asset_floor_chart.value.chart.setOption({
|
|
series: [
|
|
{ data: unSelected },
|
|
{
|
|
data: selected,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}, 0);
|
|
}
|
|
},
|
|
{
|
|
deep: true,
|
|
}
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<!-- <Loading class="absolute" /> -->
|
|
<EffectScatter
|
|
id="system_floor_chart"
|
|
ref="asset_floor_chart"
|
|
class="min-h-full bg-white"
|
|
/>
|
|
|
|
<!-- <div class="text-lg" v-if="!currentFloor?.key">尚未上傳樓層平面圖</div> -->
|
|
</template>
|
|
|
|
<style lang="scss" scoped></style>
|