274 lines
8.2 KiB
Vue
274 lines
8.2 KiB
Vue
<script setup>
|
|
import { RouterView, useRoute } from 'vue-router';
|
|
import { computed, watch, provide, ref, onMounted, onBeforeUnmount } from "vue";
|
|
import SystemFloorBar from './components/SystemFloorBar.vue';
|
|
import useBuildingStore from "@/stores/useBuildingStore";
|
|
import ForgeForSystem from "@/components/forge/ForgeForSystem.vue";
|
|
import { getSystemDevices, getSystemRealTime } from "@/apis/system";
|
|
import { getOperationCompanyList } from "@/apis/operation";
|
|
import { getAssetSingle, getAssetFloorList } from "@/apis/asset";
|
|
import SystemSubBar from './components/SystemSubBar.vue';
|
|
import SystemInfoModal from './components/SystemInfoModal.vue';
|
|
import SystemMain from "./SystemMain.vue";
|
|
import SystemMode from './components/SystemMode.vue';
|
|
import SystemFloor from './SystemFloor.vue';
|
|
import { twMerge } from 'tailwind-merge';
|
|
import dayjs from "dayjs";
|
|
|
|
const buildingStore = useBuildingStore()
|
|
|
|
const statusList = computed(() => {
|
|
const sub = buildingStore.selectedSystem
|
|
|
|
if (sub) {
|
|
return {
|
|
device_normal_color: sub.device_normal_color,
|
|
device_normal_text: sub.device_normal_text,
|
|
device_close_color: sub.device_close_color,
|
|
device_close_text: sub.device_close_text,
|
|
device_error_color: sub.device_error_color,
|
|
device_error_text: sub.device_error_text
|
|
}
|
|
}
|
|
return null
|
|
})
|
|
|
|
const raw_data = ref([]);
|
|
const data = ref([]); // filter data
|
|
const route = useRoute();
|
|
const floors = ref([]);
|
|
const companyOptions = ref([]);
|
|
const selected_dbid = ref([]);
|
|
|
|
const getFloors = async () => {
|
|
const res = await getAssetFloorList();
|
|
floors.value = res.data[0]?.floors.map((d) => ({ ...d, key: d.floor_guid }));
|
|
};
|
|
|
|
const getCompany = async () => {
|
|
const res = await getOperationCompanyList();
|
|
companyOptions.value = res.data.map((d) => ({ ...d, key: d.id }));
|
|
};
|
|
|
|
const getData = async () => {
|
|
if (!route.params.sub_system_id) return
|
|
const res = await getSystemDevices({
|
|
sub_system_tag: route.params.sub_system_id,
|
|
building_tag: buildingStore.selectedBuilding?.building_tag,
|
|
})
|
|
const devices = res.data.map(d => ({
|
|
...d,
|
|
key: d.full_name,
|
|
device_list: d.device_list.map((dev, index) => ({
|
|
...dev,
|
|
forge_dbid: parseInt(dev.forge_dbid),
|
|
room_dbid: parseInt(dev.room_dbid),
|
|
device_coordinate_3d: dev.device_coordinate_3d ? JSON.parse(dev.device_coordinate_3d) : "",
|
|
alarmMsg: "",
|
|
is_show: true,
|
|
currentColor: dev.device_normal_point_color,
|
|
spriteDbId: 10 + dev.main_id,
|
|
sensorTypes: dev.points.map(({ points }) => points),
|
|
floor_guid: d.floor_guid,
|
|
is2DActive: false
|
|
})),
|
|
}));
|
|
|
|
raw_data.value = devices
|
|
data.value = devices
|
|
console.log("devices", res.data,devices)
|
|
}
|
|
|
|
const subscribeData = ref([]); // flat data
|
|
|
|
const getSubData = (value) => {
|
|
let items = [];
|
|
value.forEach((device) => {
|
|
items = [
|
|
...items,
|
|
...device.device_list
|
|
];
|
|
});
|
|
return items
|
|
}
|
|
|
|
watch(raw_data, (newValue) => {
|
|
if (route.query.gas) {
|
|
updateDataByGas(route.query.gas)
|
|
} else {
|
|
const items = getSubData(newValue)
|
|
data.value = newValue;
|
|
subscribeData.value = items;
|
|
}
|
|
});
|
|
|
|
const updateDataByGas = (gas) => {
|
|
|
|
let update_values = []
|
|
if (gas === "all") {
|
|
update_values = raw_data.value
|
|
} else {
|
|
update_values = raw_data.value.map((d) => (
|
|
{
|
|
...d,
|
|
device_list: d.device_list.filter(({ points }) => points.some(({ points: p }) => p === gas))
|
|
}
|
|
))
|
|
}
|
|
data.value = update_values
|
|
subscribeData.value = getSubData(update_values);
|
|
}
|
|
|
|
watch(
|
|
() => buildingStore.selectedBuilding,
|
|
(newBuilding) => {
|
|
if (Boolean(newBuilding)) {
|
|
getData();
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
deep: true,
|
|
}
|
|
);
|
|
|
|
watch(
|
|
() => route.params.sub_system_id,
|
|
(newRoute, oldRoute) => {
|
|
if (buildingStore.selectedBuilding && newRoute !== oldRoute) {
|
|
getData();
|
|
}
|
|
}
|
|
);
|
|
|
|
onMounted(() => {
|
|
getFloors();
|
|
getCompany();
|
|
});
|
|
|
|
const currentFloor = ref(null);
|
|
|
|
const updateCurrentFloor = (floor) => {
|
|
currentFloor.value = floor;
|
|
}
|
|
|
|
const realtimeData = ref([])
|
|
const timeId = ref(null)
|
|
const getAllDeviceRealtime = () => {
|
|
timeId.value = setInterval(async () => {
|
|
const res = await getSystemRealTime(subscribeData.value.map(d => d.device_number))
|
|
console.log(res.data)
|
|
realtimeData.value = res.data
|
|
}, 10000)
|
|
}
|
|
|
|
watch(subscribeData, (newValue) => {
|
|
timeId.value && clearInterval(timeId.value)
|
|
newValue.length > 0 && getAllDeviceRealtime()
|
|
}, { deep: true, immediate: true })
|
|
|
|
provide("system_deviceList", { data, subscribeData, currentFloor, updateCurrentFloor, updateDataByGas, realtimeData })
|
|
|
|
const selectedDevice = ref(null);
|
|
const selectedDeviceCog = ref({});
|
|
// const selectedDevice = computed(() => {
|
|
// return {
|
|
// ...currentInfo.value,
|
|
// points: realtimeData.value.find(({ device_number }) => device_number === currentInfo.value?.value.device_number)
|
|
// }
|
|
// });
|
|
// 傳遞目前點擊資訊
|
|
const isMobile = (e) => {
|
|
return e.pointerType !== "mouse" && e.type !== "click"; // is mobile
|
|
};
|
|
|
|
const getCurrentInfoModalData = async (e, position, value) => {
|
|
if (value.main_id) {
|
|
const res = await getAssetSingle(value.main_id);
|
|
if (res.isSuccess) {
|
|
selectedDeviceCog.value = {
|
|
...res.data,
|
|
key: res.data.id,
|
|
floor: floors.value.find(
|
|
({ floor_guid }) => res.data.floor_guid === floor_guid
|
|
)?.full_name,
|
|
company: companyOptions.value.find(
|
|
({ id }) => res.data.operation_id === id
|
|
)?.name,
|
|
buying_date: res.data?.buying_date
|
|
? dayjs(res.data.buying_date).format("YYYY-MM-DD")
|
|
: "",
|
|
created_at: res.data?.created_at
|
|
? dayjs(res.data.created_at).format("YYYY-MM-DD")
|
|
: "",
|
|
};
|
|
}
|
|
}
|
|
const mobile = isMobile(e);
|
|
selectedDevice.value = {
|
|
initPos: { left: `50%`, top: `50%` },
|
|
value,
|
|
isMobile: mobile,
|
|
};
|
|
document.getElementById('system_info_modal').showModal();
|
|
};
|
|
|
|
const selectedDeviceRealtime = computed(() => realtimeData.value?.find(({ device_number }) => device_number === selectedDevice.value?.value?.device_number)?.data)
|
|
|
|
const clearSelectedDeviceInfo = () => {
|
|
|
|
selectedDevice.value.value = null;
|
|
}
|
|
|
|
provide("system_selectedDevice", { selectedDeviceRealtime, selectedDevice, getCurrentInfoModalData, clearSelectedDeviceInfo, selectedDeviceCog, selected_dbid })
|
|
|
|
onBeforeUnmount(() => {
|
|
clearInterval(timeId.value);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<SystemInfoModal :data="selectedDevice" />
|
|
<SystemFloorBar />
|
|
<div class="grid grid-cols-2 gap-5 mt-8 mb-4">
|
|
<div class="col-span-1 h-[calc(100vh-170px)] flex flex-col justify-start">
|
|
<div>
|
|
<div class="flex mb-4 items-center">
|
|
<span class="flex items-center mr-3" v-if="statusList?.device_normal_text">
|
|
<span class="w-7 h-7 rounded-full inline-block mr-1"
|
|
:style="{ backgroundColor: statusList.device_normal_color }"></span>
|
|
<span>{{ statusList.device_normal_text }}</span>
|
|
</span>
|
|
<span class="flex items-center mr-3" v-if="statusList?.device_close_text">
|
|
<span class="w-7 h-7 rounded-full inline-block mr-1"
|
|
:style="{ backgroundColor: statusList.device_close_color }"></span>
|
|
<span>{{ statusList.device_close_text }}</span>
|
|
</span>
|
|
<span class="flex items-center mr-3" v-if="statusList?.device_error_text">
|
|
<span class="w-7 h-7 rounded-full inline-block mr-1"
|
|
:style="{ backgroundColor: statusList.device_error_color }"></span>
|
|
<span>{{ statusList.device_error_text }}</span>
|
|
</span>
|
|
</div>
|
|
<SystemSubBar class="mt-2 mb-4" />
|
|
</div>
|
|
<div class="h-full pr-2 overflow-y-auto">
|
|
<RouterView />
|
|
</div>
|
|
</div>
|
|
<div class="col-span-1 h-full flex flex-col justify-between">
|
|
<SystemMode />
|
|
<div class="h-full relative">
|
|
<SystemFloor
|
|
:class="twMerge('absolute h-full w-full', route.query.mode === '2D' ? 'opacity-100 z-10' : 'opacity-0 z-0')" />
|
|
<div
|
|
:class="twMerge('absolute h-full w-full', route.query.mode === '3D' ? 'opacity-100 z-10' : 'opacity-0 z-0')">
|
|
<ForgeForSystem :initialData="{}" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<style lang='scss' scoped></style> |