init info modal | 樣式修改
This commit is contained in:
parent
355fc12499
commit
bf5d6e6eb1
@ -1,2 +1,3 @@
|
|||||||
export const GET_SYSTEM_FLOOR_LIST_API = `/api/Device/GetFloor`;
|
export const GET_SYSTEM_FLOOR_LIST_API = `/api/Device/GetFloor`;
|
||||||
export const GET_SYSTEM_DEVICE_LIST_API = `/api/Device/GetDeviceList`;
|
export const GET_SYSTEM_DEVICE_LIST_API = `/api/Device/GetDeviceList`;
|
||||||
|
export const GET_SYSTEM_REALTIME_API = `/api/Device/GetRealTimeData`;
|
@ -1,4 +1,8 @@
|
|||||||
import { GET_SYSTEM_FLOOR_LIST_API, GET_SYSTEM_DEVICE_LIST_API } from "./api";
|
import {
|
||||||
|
GET_SYSTEM_FLOOR_LIST_API,
|
||||||
|
GET_SYSTEM_DEVICE_LIST_API,
|
||||||
|
GET_SYSTEM_REALTIME_API,
|
||||||
|
} from "./api";
|
||||||
import instance from "@/util/request";
|
import instance from "@/util/request";
|
||||||
import apihandler from "@/util/apihandler";
|
import apihandler from "@/util/apihandler";
|
||||||
|
|
||||||
@ -30,3 +34,11 @@ export const getSystemDevices = async ({
|
|||||||
code: res.code,
|
code: res.code,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getSystemRealTime = async (device_list) => {
|
||||||
|
const res = await instance.post(GET_SYSTEM_REALTIME_API, { device_list });
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -13,7 +13,7 @@ import { twMerge } from "tailwind-merge";
|
|||||||
import hexToRgb from "@/util/hexToRgb";
|
import hexToRgb from "@/util/hexToRgb";
|
||||||
import getModalPosition from "@/util/getModalPosition";
|
import getModalPosition from "@/util/getModalPosition";
|
||||||
import useSystemStatusByBaja from "@/hooks/baja/useSystemStatusByBaja";
|
import useSystemStatusByBaja from "@/hooks/baja/useSystemStatusByBaja";
|
||||||
import ForgeInfoModal from "./ForgeInfoModal.vue";
|
import ForgeInfoModal from "../../views/system/components/SystemInfoModal.vue";
|
||||||
import useAlarmStore from "@/stores/useAlarmStore";
|
import useAlarmStore from "@/stores/useAlarmStore";
|
||||||
import useForgeSprite from "@/hooks/forge/useForgeSprite";
|
import useForgeSprite from "@/hooks/forge/useForgeSprite";
|
||||||
|
|
||||||
@ -64,6 +64,10 @@ const initViewer = (container) => {
|
|||||||
let viewer = new Autodesk.Viewing.GuiViewer3D(container, config);
|
let viewer = new Autodesk.Viewing.GuiViewer3D(container, config);
|
||||||
Autodesk.Viewing.Private.InitParametersSetting.alpha = true;
|
Autodesk.Viewing.Private.InitParametersSetting.alpha = true;
|
||||||
viewer.start();
|
viewer.start();
|
||||||
|
viewer.setGroundShadow(false);
|
||||||
|
viewer.impl.renderer().setClearAlpha(0);
|
||||||
|
viewer.impl.glrenderer().setClearColor(0xffffff, 0);
|
||||||
|
viewer.impl.invalidate(true);
|
||||||
resolve(viewer);
|
resolve(viewer);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -79,6 +83,7 @@ const loadModel = (viewer, filePath) => {
|
|||||||
(model) => {
|
(model) => {
|
||||||
viewer.impl.invalidate(true);
|
viewer.impl.invalidate(true);
|
||||||
viewer.fitToView();
|
viewer.fitToView();
|
||||||
|
updateDataVisualization(viewer)
|
||||||
resolve(model);
|
resolve(model);
|
||||||
console.log("模型加載完成");
|
console.log("模型加載完成");
|
||||||
},
|
},
|
||||||
@ -147,10 +152,21 @@ const initForge = async () => {
|
|||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
||||||
const viewer = await initViewer(forgeDom.value)
|
const viewer = await initViewer(forgeDom.value)
|
||||||
const filePath = `${FILE_BASEURL}/upload/forge/0.svf`;
|
const filePath = `${FILE_BASEURL}/upload/forge/0.svf`;
|
||||||
await loadModel(viewer, filePath)
|
await loadModel(viewer, filePath)
|
||||||
|
viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT,
|
||||||
|
async function () {
|
||||||
|
console.log(
|
||||||
|
"Autodesk.Viewing.GEOMETRY_LOADED_EVENT",
|
||||||
|
viewer.isLoadDone()
|
||||||
|
);
|
||||||
|
// updateForgeViewer(viewer);
|
||||||
|
createSprites()
|
||||||
|
hideAllObjects();
|
||||||
|
})
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { defineProps, onMounted, ref, watch } from "vue";
|
|
||||||
import ForgeInfoModalDesktop from "./ForgeInfoModalDesktop.vue";
|
|
||||||
import ForgeInfoModalCog from "./ForgeInfoModalCog.vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
data: Object,
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentTab = ref("desktop");
|
|
||||||
const tabs = {
|
|
||||||
desktop: ForgeInfoModalDesktop,
|
|
||||||
cog: ForgeInfoModalCog,
|
|
||||||
};
|
|
||||||
|
|
||||||
const changeOpenKey = (key) => {
|
|
||||||
currentTab.value = key;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCancel = () => {
|
|
||||||
forge_info_modal.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
const position = ref({
|
|
||||||
left: "0px",
|
|
||||||
top: "0px",
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.data,
|
|
||||||
(newValue) => {
|
|
||||||
console.log(newValue);
|
|
||||||
position.value = newValue.initPos;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Modal
|
|
||||||
id="forge_info_modal"
|
|
||||||
:onCancel="onCancel"
|
|
||||||
width="550"
|
|
||||||
:draggable="!data?.isMobile"
|
|
||||||
:backdrop="false"
|
|
||||||
:modalStyle="position"
|
|
||||||
:class="data?.isMobile ? '-translate-x-1/2 -translate-y-1/2' : ''"
|
|
||||||
>
|
|
||||||
<template #modalContent>
|
|
||||||
<div class="card bg-transparent text-white">
|
|
||||||
<div class="card-title py-2 border-b border-zinc-700 justify-between">
|
|
||||||
<h3>{{ data?.value.full_name }}</h3>
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
class="btn-link btn-text-without-border px-2"
|
|
||||||
@click="() => changeOpenKey('desktop')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
:icon="['fas', 'desktop']"
|
|
||||||
size="lg"
|
|
||||||
class="text-[#a5abb1]"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
class="btn-link btn-text-without-border px-2"
|
|
||||||
@click="() => changeOpenKey('cog')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
:icon="['fas', 'cog']"
|
|
||||||
size="lg"
|
|
||||||
class="text-[#a5abb1]"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
<!-- <Button
|
|
||||||
type="link"
|
|
||||||
class="btn-link btn-text-without-border px-2"
|
|
||||||
@click="() => changeOpenKey('triangle')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
:icon="['fas', 'exclamation-triangle']"
|
|
||||||
size="lg"
|
|
||||||
class="text-[#a5abb1]"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
class="btn-link btn-text-without-border px-2"
|
|
||||||
@click="() => changeOpenKey('bars')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
:icon="['fas', 'bars']"
|
|
||||||
size="lg"
|
|
||||||
class="text-[#a5abb1]"
|
|
||||||
/>
|
|
||||||
</Button>-->
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
class="btn-link btn-text-without-border px-2"
|
|
||||||
@click="onCancel"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
:icon="['fas', 'times']"
|
|
||||||
size="lg"
|
|
||||||
class="text-[#a5abb1]"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body px-0">
|
|
||||||
<component :is="tabs[currentTab]" :data="data"></component>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</Modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
@ -1,34 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { defineProps, watch, computed } from "vue";
|
|
||||||
import { useRoute } from "vue-router";
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
data: Object,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pxRoute = computed(() =>
|
|
||||||
route.path === "/dashboard" ? "GraphicM" : "GraphicU"
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.data,
|
|
||||||
(newValue) => {
|
|
||||||
console.log(newValue, newValue.value.device_number);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const device_px_route = computed(() =>
|
|
||||||
props.data?.value.device_number.replaceAll("_", "/")
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<iframe
|
|
||||||
v-if="data"
|
|
||||||
:src="`/ord?station:%7Cslot:/${device_px_route}|view:${pxRoute}?fullScreen=true`"
|
|
||||||
style="width: 500px; height: 350px"
|
|
||||||
></iframe>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
@ -1,4 +1,7 @@
|
|||||||
export default function useForgeHeatmap(){
|
import { watch, inject, markRaw, ref } from "vue";
|
||||||
|
|
||||||
|
export default function useForgeHeatmap(dataVizExtn, forgeViewer){
|
||||||
|
const { subscribeData } = inject("system_deviceList");
|
||||||
|
|
||||||
const createHeatMap = async (heatMapName) => {
|
const createHeatMap = async (heatMapName) => {
|
||||||
const {
|
const {
|
||||||
@ -10,7 +13,7 @@ export default function useForgeHeatmap(){
|
|||||||
const shadingGroup = new SurfaceShadingGroup(`iot_heatmap_${heatMapName}`);
|
const shadingGroup = new SurfaceShadingGroup(`iot_heatmap_${heatMapName}`);
|
||||||
const rooms = new Map();
|
const rooms = new Map();
|
||||||
|
|
||||||
for (const { id, roomDbId, position, sensorTypes } of deviceList.value) {
|
for (const { id, roomDbId, position, sensorTypes } of subscribeData.value) {
|
||||||
if (!id || roomDbId == -1 || !roomDbId) {
|
if (!id || roomDbId == -1 || !roomDbId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -28,20 +31,19 @@ export default function useForgeHeatmap(){
|
|||||||
shadingData.addChild(shadingGroup);
|
shadingData.addChild(shadingGroup);
|
||||||
shadingData.initialize(forgeViewer.value?.model);
|
shadingData.initialize(forgeViewer.value?.model);
|
||||||
|
|
||||||
await dataVizExtension.value.setupSurfaceShading(
|
await dataVizExtn.value.setupSurfaceShading(
|
||||||
forgeViewer.value.model,
|
forgeViewer.value.model,
|
||||||
shadingData
|
shadingData
|
||||||
);
|
);
|
||||||
dataVizExtension.value.registerSurfaceShadingColors(
|
dataVizExtn.value.registerSurfaceShadingColors(
|
||||||
"temperature",
|
heatMapName,
|
||||||
[0x0000ff, 0x00ff00, 0xffff00, 0xff0000]
|
[0x0000ff, 0x00ff00, 0xffff00, 0xff0000]
|
||||||
);
|
);
|
||||||
dataVizExtension.value.renderSurfaceShading(
|
dataVizExtn.value.renderSurfaceShading(
|
||||||
`iot_heatmap_${heatMapName}`,
|
`iot_heatmap_${heatMapName}`,
|
||||||
"temperature",
|
heatMapName,
|
||||||
getSensorValue
|
getSensorValue
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(dataVizExtension.value);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -40,20 +40,22 @@ export default function useForgeSprite() {
|
|||||||
const viewableData = new DataVizCore.ViewableData();
|
const viewableData = new DataVizCore.ViewableData();
|
||||||
viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels
|
viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels
|
||||||
subscribeData.value?.forEach((d, index) => {
|
subscribeData.value?.forEach((d, index) => {
|
||||||
const position = d.device_coordinate_3d;
|
if (d.device_coordinate_3d) {
|
||||||
style.color = new THREE.Color(hexToRgb(d.device_normal_color));
|
const position = d.device_coordinate_3d;
|
||||||
const viewable = new DataVizCore.SpriteViewable(
|
style.color = new THREE.Color(hexToRgb(d.device_normal_color));
|
||||||
position,
|
const viewable = new DataVizCore.SpriteViewable(
|
||||||
style,
|
position,
|
||||||
d.spriteDbId
|
style,
|
||||||
);
|
d.spriteDbId
|
||||||
viewableData.addViewable(viewable);
|
);
|
||||||
|
viewableData.addViewable(viewable);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
await viewableData.finish();
|
await viewableData.finish();
|
||||||
dataVizExtn.value.addViewables(viewableData);
|
dataVizExtn.value.addViewables(viewableData);
|
||||||
|
|
||||||
NOP_VIEWER.addEventListener(DataVizCore.MOUSE_CLICK, onSpriteClicked);
|
forgeViewer.value.addEventListener(DataVizCore.MOUSE_CLICK, onSpriteClicked);
|
||||||
NOP_VIEWER.addEventListener(
|
forgeViewer.value.addEventListener(
|
||||||
Autodesk.Viewing.SELECTION_CHANGED_EVENT,
|
Autodesk.Viewing.SELECTION_CHANGED_EVENT,
|
||||||
onSpriteClicked
|
onSpriteClicked
|
||||||
);
|
);
|
||||||
@ -80,17 +82,17 @@ export default function useForgeSprite() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const hideAllObjects = () => {
|
const hideAllObjects = () => {
|
||||||
const tree = NOP_VIEWER.model?.getData().instanceTree;
|
const tree = forgeViewer.value.model.getInstanceTree();
|
||||||
const allDbIdsStr = Object.keys(tree.nodeAccess.dbIdToIndex);
|
const allDbIdsStr = Object.keys(tree.nodeAccess.dbIdToIndex);
|
||||||
for (var i = 0; i < allDbIdsStr.length; i++) {
|
for (var i = 0; i < allDbIdsStr.length; i++) {
|
||||||
NOP_VIEWER.hide(parseInt(allDbIdsStr[i]));
|
forgeViewer.value.hide(parseInt(allDbIdsStr[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribeData.value.forEach((value, index) => {
|
subscribeData.value.forEach((value, index) => {
|
||||||
NOP_VIEWER.show(value.forge_dbid);
|
forgeViewer.value.show(value.forge_dbid);
|
||||||
});
|
});
|
||||||
|
|
||||||
NOP_VIEWER.impl.invalidate(true);
|
forgeViewer.value.impl.invalidate(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -6,6 +6,7 @@ import useBuildingStore from "@/stores/useBuildingStore";
|
|||||||
import ForgeForSystem from "@/components/forge/ForgeForSystem.vue";
|
import ForgeForSystem from "@/components/forge/ForgeForSystem.vue";
|
||||||
import { getSystemDevices } from "@/apis/system";
|
import { getSystemDevices } from "@/apis/system";
|
||||||
import SystemSubBar from './components/SystemSubBar.vue';
|
import SystemSubBar from './components/SystemSubBar.vue';
|
||||||
|
import SystemInfoModal from './components/SystemInfoModal.vue';
|
||||||
|
|
||||||
const buildingStore = useBuildingStore()
|
const buildingStore = useBuildingStore()
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ const statusList = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const raw_data = ref([])
|
const raw_data = ref([])
|
||||||
const data = ref([])
|
const data = ref([]) // filter data
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
@ -34,12 +35,26 @@ const getData = async () => {
|
|||||||
sub_system_tag: route.params.sub_system_id,
|
sub_system_tag: route.params.sub_system_id,
|
||||||
building_tag: buildingStore.selectedBuilding?.building_tag,
|
building_tag: buildingStore.selectedBuilding?.building_tag,
|
||||||
})
|
})
|
||||||
const data = res.data.map(d => ({ ...d, key: d.full_name }));
|
const data = res.data.map(d => ({
|
||||||
|
...d, key: d.full_name, device_list: d.device_list.map((d, index) => ({
|
||||||
|
...d,
|
||||||
|
forge_dbid: parseInt(d.forge_dbid),
|
||||||
|
device_coordinate_3d: d.device_coordinate_3d
|
||||||
|
? JSON.parse(d.device_coordinate_3d)
|
||||||
|
: { x: 0, y: 0 },
|
||||||
|
alarmMsg: "",
|
||||||
|
is_show: true,
|
||||||
|
currentColor: d.device_normal_point_color,
|
||||||
|
spriteDbId: 10 + index,
|
||||||
|
sensorTypes: d.points.map(({ points }) => points),
|
||||||
|
points: d.points.map((p) => ({ ...p, value: "" }))
|
||||||
|
})),
|
||||||
|
}));
|
||||||
raw_data.value = data
|
raw_data.value = data
|
||||||
data.value = data
|
data.value = data
|
||||||
}
|
}
|
||||||
|
|
||||||
const subscribeData = ref([]);
|
const subscribeData = ref([]); // flat data
|
||||||
|
|
||||||
const getSubPoint = (normal, close, error, sub_points) => {
|
const getSubPoint = (normal, close, error, sub_points) => {
|
||||||
let points = {
|
let points = {
|
||||||
@ -56,23 +71,7 @@ const getSubData = (value) => {
|
|||||||
value.forEach((device) => {
|
value.forEach((device) => {
|
||||||
items = [
|
items = [
|
||||||
...items,
|
...items,
|
||||||
...device.device_list.map((d, index) => ({
|
...device.device_list
|
||||||
...d,
|
|
||||||
forge_dbid: parseInt(d.forge_dbid),
|
|
||||||
device_coordinate_3d: d.device_coordinate_3d
|
|
||||||
? JSON.parse(d.device_coordinate_3d)
|
|
||||||
: { x: 0, y: 0 },
|
|
||||||
// points: getSubPoint(
|
|
||||||
// d.device_normal_point_name,
|
|
||||||
// d.device_close_point_name,
|
|
||||||
// d.device_error_point_name,
|
|
||||||
// d.points
|
|
||||||
// ),
|
|
||||||
alarmMsg: "",
|
|
||||||
is_show: true,
|
|
||||||
currentColor: d.device_normal_point_color,
|
|
||||||
spriteDbId: 10 + index,
|
|
||||||
})),
|
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
data.value = raw_data.value;
|
data.value = raw_data.value;
|
||||||
@ -83,6 +82,10 @@ watch(raw_data, (newValue) => {
|
|||||||
updateDataByGas("all")
|
updateDataByGas("all")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(data, (newValue) => {
|
||||||
|
console.log(newValue);
|
||||||
|
})
|
||||||
|
|
||||||
const updateDataByGas = (gas) => {
|
const updateDataByGas = (gas) => {
|
||||||
console.log(gas)
|
console.log(gas)
|
||||||
if (gas === "all") {
|
if (gas === "all") {
|
||||||
@ -112,12 +115,40 @@ const updateCurrentFloor = (floor) => {
|
|||||||
|
|
||||||
provide("system_deviceList", { data, subscribeData, currentFloor, updateCurrentFloor, updateDataByGas })
|
provide("system_deviceList", { data, subscribeData, currentFloor, updateCurrentFloor, updateDataByGas })
|
||||||
|
|
||||||
|
|
||||||
|
// 傳遞目前點擊資訊
|
||||||
|
const currentInfoModalData = ref(null);
|
||||||
|
const isMobile = (pointerType) => {
|
||||||
|
// let flag =
|
||||||
|
// /phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone/gi.test(
|
||||||
|
// navigator.userAgent
|
||||||
|
// );
|
||||||
|
// console.log("isMobile", flag);
|
||||||
|
return pointerType !== "mouse"; // is desktop
|
||||||
|
};
|
||||||
|
const getCurrentInfoModalData = (e, position, value) => {
|
||||||
|
const mobile = isMobile(e.pointerType);
|
||||||
|
selectedDevice.value = {
|
||||||
|
initPos: mobile
|
||||||
|
? { left: `50%`, top: `50%` }
|
||||||
|
: { left: `${position.left}px`, top: `${position.top}px` },
|
||||||
|
value,
|
||||||
|
isMobile: mobile,
|
||||||
|
};;
|
||||||
|
document.getElementById('system_info_modal').showModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectedDevice = ref(null);
|
||||||
|
|
||||||
|
provide("system_selectedDevice", { selectedDevice, getCurrentInfoModalData })
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<SystemInfoModal :data="selectedDevice" />
|
||||||
<SystemFloorBar />
|
<SystemFloorBar />
|
||||||
<div class="grid grid-cols-2 gap-5 mt-8 mb-4">
|
<div class="grid grid-cols-2 gap-5 mt-8 mb-4">
|
||||||
<div class="col-span-1 h-[80vh] flex flex-col justify-between">
|
<div class="col-span-1 h-[80vh] flex flex-col justify-start">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex mb-4 items-center">
|
<div class="flex mb-4 items-center">
|
||||||
<span class="flex items-center mr-3" v-if="statusList?.device_normal_text">
|
<span class="flex items-center mr-3" v-if="statusList?.device_normal_text">
|
||||||
@ -146,6 +177,7 @@ provide("system_deviceList", { data, subscribeData, currentFloor, updateCurrentF
|
|||||||
<ForgeForSystem :initialData="{}" />
|
<ForgeForSystem :initialData="{}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped></style>
|
@ -38,7 +38,7 @@ watch([() => currentFloor, () => asset_floor_chart], ([newValue, newChart]) => {
|
|||||||
asset_floor_chart.value.updateSvg(
|
asset_floor_chart.value.updateSvg(
|
||||||
{
|
{
|
||||||
full_name: newValue.value?.title,
|
full_name: newValue.value?.title,
|
||||||
path: `${FILE_BASEURL}/upload/floor_map/${newValue.value.map_url}`,
|
path: `${FILE_BASEURL}/${newValue.value.map_url}`,
|
||||||
},
|
},
|
||||||
|
|
||||||
defaultOption(newValue.value?.title, subscribeData.value.filter(d => d.device_coordinate).map(d => JSON.parse(d.device_coordinate)))
|
defaultOption(newValue.value?.title, subscribeData.value.filter(d => d.device_coordinate).map(d => JSON.parse(d.device_coordinate)))
|
||||||
|
@ -4,6 +4,7 @@ import { inject } from "vue"
|
|||||||
const { data } = inject("system_deviceList")
|
const { data } = inject("system_deviceList")
|
||||||
|
|
||||||
|
|
||||||
|
const { getCurrentInfoModalData } = inject("system_selectedDevice")
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -23,10 +24,14 @@ const { data } = inject("system_deviceList")
|
|||||||
<span class="w-8 h-8" v-else></span>
|
<span class="w-8 h-8" v-else></span>
|
||||||
<span>{{ device.full_name }}</span>
|
<span>{{ device.full_name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="sec03">
|
<div class="flex justify-between">
|
||||||
<span></span>
|
<div class="sec03">
|
||||||
<span>狀態:</span>
|
<span></span>
|
||||||
<span></span>
|
<span>狀態:</span>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
|
<button class="btn-text border-0 "
|
||||||
|
@click.stop.prevent="(e) => getCurrentInfoModalData(e, { left: e.clientX, top: e.clientY }, device)">詳細資料</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -52,6 +57,10 @@ const { data } = inject("system_deviceList")
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item .btn-text {
|
||||||
|
@apply hover:bg-transparent focus-within:bg-transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
.equipment-show .item .sec01 span:nth-child(1) {
|
.equipment-show .item .sec01 span:nth-child(1) {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { getSystemFloors } from "@/apis/system"
|
import { getAssetFloorList } from "@/apis/asset";
|
||||||
import { onMounted, ref, watch, inject } from 'vue';
|
import { onMounted, ref, watch, inject } from 'vue';
|
||||||
import useBuildingStore from "@/stores/useBuildingStore";
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
import useActiveBtn from "@/hooks/useActiveBtn"
|
import useActiveBtn from "@/hooks/useActiveBtn"
|
||||||
@ -14,18 +14,20 @@ const { updateCurrentFloor } = inject("system_deviceList")
|
|||||||
|
|
||||||
const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
|
const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
|
||||||
const getFloors = async () => {
|
const getFloors = async () => {
|
||||||
const res = await getSystemFloors(store.selectedBuilding?.building_tag, route.params.sub_system_id)
|
const res = await getAssetFloorList()
|
||||||
|
let data = res.data.find(d => d.building_tag === store.selectedBuilding?.building_tag)
|
||||||
|
console.log(data)
|
||||||
setItems([
|
setItems([
|
||||||
{
|
{
|
||||||
title: "總覽",
|
title: "總覽",
|
||||||
key: "main",
|
key: "main",
|
||||||
active: route.params.floor_id ? false : true,
|
active: route.params.floor_id ? false : true,
|
||||||
},
|
},
|
||||||
...res.data.map((d, idx) => ({
|
...data.floors.map((d, idx) => ({
|
||||||
title: d.floor_tag,
|
title: d.full_name,
|
||||||
key: d.floor_guid,
|
key: d.floor_guid,
|
||||||
active: route.params.floor_id === d.floor_guid,
|
active: route.params.floor_id === d.floor_guid,
|
||||||
map_url: d.floor_map_name
|
map_url: d.floor_map_url + ".svg"
|
||||||
}))
|
}))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
31
src/views/system/components/SystemInfoModal.vue
Normal file
31
src/views/system/components/SystemInfoModal.vue
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<script setup>
|
||||||
|
import { inject, ref, watch } from "vue";
|
||||||
|
import SystemInfoModalContent from "./SystemInfoModalContent.vue";
|
||||||
|
|
||||||
|
|
||||||
|
const { selectedDevice: data } = inject("system_selectedDevice")
|
||||||
|
|
||||||
|
const position = ref({
|
||||||
|
left: "0px",
|
||||||
|
top: "0px",
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => data,
|
||||||
|
(newValue) => {
|
||||||
|
console.log(newValue);
|
||||||
|
position.value = newValue.initPos;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal id="system_info_modal" :onCancel="onCancel" width="600" :draggable="!data?.isMobile" :backdrop="false"
|
||||||
|
:modalStyle="position" :class="data?.isMobile ? '-translate-x-1/2 -translate-y-1/2' : ''">
|
||||||
|
<template #modalContent>
|
||||||
|
<SystemInfoModalContent />
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
73
src/views/system/components/SystemInfoModalContent.vue
Normal file
73
src/views/system/components/SystemInfoModalContent.vue
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps, inject, ref, watch } from "vue";
|
||||||
|
import SystemInfoModalDesktop from "./SystemInfoModalDesktop.vue";
|
||||||
|
import SystemInfoModalCog from "./SystemInfoModalCog.vue";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
|
||||||
|
const { selectedDevice: data } = inject("system_selectedDevice")
|
||||||
|
|
||||||
|
|
||||||
|
const currentTab = ref("desktop");
|
||||||
|
const tabs = {
|
||||||
|
desktop: SystemInfoModalDesktop,
|
||||||
|
cog: SystemInfoModalCog,
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeOpenKey = (key) => {
|
||||||
|
currentTab.value = key;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCancel = () => {
|
||||||
|
currentTab.value = "desktop";
|
||||||
|
document.getElementById('system_info_modal').close();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="card bg-transparent text-white">
|
||||||
|
<div class="card-title py-2 border-b border-zinc-700 justify-between">
|
||||||
|
<h3>{{ data?.value.full_name }}</h3>
|
||||||
|
<div>
|
||||||
|
<Button type="link" class="btn-link btn-text-without-border px-2" @click="() => changeOpenKey('desktop')">
|
||||||
|
<font-awesome-icon :icon="['fas', 'desktop']" size="lg"
|
||||||
|
:class="twMerge(currentTab === 'desktop' ? 'text-success' : 'text-[#a5abb1]')" />
|
||||||
|
</Button>
|
||||||
|
<Button type="link" class="btn-link btn-text-without-border px-2" @click="() => changeOpenKey('cog')">
|
||||||
|
<font-awesome-icon :icon="['fas', 'cog']" size="lg"
|
||||||
|
:class="twMerge(currentTab === 'cog' ? 'text-success' : 'text-[#a5abb1]')" />
|
||||||
|
</Button>
|
||||||
|
<!-- <Button
|
||||||
|
type="link"
|
||||||
|
class="btn-link btn-text-without-border px-2"
|
||||||
|
@click="() => changeOpenKey('triangle')"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
:icon="['fas', 'exclamation-triangle']"
|
||||||
|
size="lg"
|
||||||
|
class="text-[#a5abb1]"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
class="btn-link btn-text-without-border px-2"
|
||||||
|
@click="() => changeOpenKey('bars')"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
:icon="['fas', 'bars']"
|
||||||
|
size="lg"
|
||||||
|
class="text-[#a5abb1]"
|
||||||
|
/>
|
||||||
|
</Button>-->
|
||||||
|
<Button type="link" class="btn-link btn-text-without-border px-2" @click="onCancel">
|
||||||
|
<font-awesome-icon :icon="['fas', 'times']" size="lg" class="text-[#a5abb1]" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body px-0">
|
||||||
|
<component :is="tabs[currentTab]" :data="[]"></component>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='scss' scoped></style>
|
22
src/views/system/components/SystemInfoModalDesktop.vue
Normal file
22
src/views/system/components/SystemInfoModalDesktop.vue
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<script setup>
|
||||||
|
import { inject } from "vue";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
|
const { selectedDevice } = inject("system_selectedDevice");
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
title: "屬性",
|
||||||
|
key: "points"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "值",
|
||||||
|
key: "value"
|
||||||
|
}]
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Table :loading="loading" :columns="columns" :dataSource="[]" :withStyle="false"></Table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
@ -11,10 +11,11 @@ watch(() => buildingStore, (newValue) => {
|
|||||||
newValue.selectedSystem?.points?.length > 0 && setItems(newValue.selectedSystem.points.map(d => ({
|
newValue.selectedSystem?.points?.length > 0 && setItems(newValue.selectedSystem.points.map(d => ({
|
||||||
title: d.full_name,
|
title: d.full_name,
|
||||||
key: d.points,
|
key: d.points,
|
||||||
active: false,
|
active: d.points === "Temp",
|
||||||
})))
|
})))
|
||||||
}, {
|
}, {
|
||||||
deep: true,
|
deep: true,
|
||||||
|
immediate: true
|
||||||
})
|
})
|
||||||
|
|
||||||
const onClick = (item) => {
|
const onClick = (item) => {
|
||||||
@ -25,9 +26,8 @@ const onClick = (item) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<template v-if="items.length > 0">
|
<template v-if="buildingStore.selectedSystem?.points?.length > 0">
|
||||||
<ButtonGroup :items="items" :withLine="false" className="btn-xs rounded-md" :onclick="(e, item) => onClick(item)" />
|
<ButtonGroup :items="items" :withLine="false" className="btn-xs rounded-md" :onclick="(e, item) => onClick(item)" />
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user