歷史資料sidebar加樓層
This commit is contained in:
parent
334d0d5212
commit
b830749965
@ -1,3 +1,3 @@
|
|||||||
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
VITE_API_BASEURL = "https://192.168.0.206:8060"
|
||||||
VITE_FILE_API_BASEURL = "https://ibms-cvilux.production.mjmtech.com.tw"
|
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
||||||
VITE_FORGE_BASEURL = "http://localhost:5173"
|
VITE_FORGE_BASEURL = "http://localhost:5173"
|
@ -1,3 +1,3 @@
|
|||||||
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
VITE_API_BASEURL = "https://192.168.0.206:8060"
|
||||||
VITE_FILE_API_BASEURL = "https://ibms-cvilux.production.mjmtech.com.tw"
|
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
||||||
VITE_FORGE_BASEURL = "http://202.39.218.221:8080/file/netzero"
|
VITE_FORGE_BASEURL = "http://202.39.218.221:8080/file/netzero"
|
@ -9,7 +9,7 @@
|
|||||||
href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.css"
|
href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.css"
|
||||||
/>
|
/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>瀚荃監控系統</title>
|
<title>Cvilux EMS</title>
|
||||||
<script src="https://code.jquery.com/jquery-3.7.1.js"></script>
|
<script src="https://code.jquery.com/jquery-3.7.1.js"></script>
|
||||||
<script src="https://code.jquery.com/ui/1.13.3/jquery-ui.js"></script>
|
<script src="https://code.jquery.com/ui/1.13.3/jquery-ui.js"></script>
|
||||||
<script type="text/javascript" src="/requirejs/config.js"></script>
|
<script type="text/javascript" src="/requirejs/config.js"></script>
|
||||||
|
@ -25,14 +25,14 @@ onMounted(() => {
|
|||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
role="button"
|
role="button"
|
||||||
class="text-white ml-8 text-xl font-semiLight "
|
class="text-white ml-8 text-lg font-semiLight "
|
||||||
>
|
>
|
||||||
{{ store.selectedBuilding?.full_name }}
|
{{ store.selectedBuilding?.full_name }}
|
||||||
<font-awesome-icon :icon="['fas', 'angle-down']" class="ml-1"/>
|
<font-awesome-icon :icon="['fas', 'angle-down']" class="ml-1"/>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="dropdown-content left-8 translate-y-2 z-[1] menu py-3 shadow rounded w-32 bg-[#4c625e] border text-center"
|
class="dropdown-content left-8 translate-y-2 z-[1] menu py-3 shadow rounded bg-[#4c625e] border text-center"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
class="text-white my-1 text-base"
|
class="text-white my-1 text-base"
|
||||||
|
@ -162,11 +162,11 @@ onMounted(() => {
|
|||||||
color: #93c0dc;
|
color: #93c0dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .ant-menu-submenu-title:active {
|
:deep(.ant-menu-submenu-title:active) {
|
||||||
color: #35759d !important;
|
color: #35759d !important;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
::v-deep .ant-menu-item:not(.ant-menu-item-selected) {
|
:deep(.ant-menu-item:not(.ant-menu-item-selected)) {
|
||||||
&::before {
|
&::before {
|
||||||
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat z-10 grayscale;
|
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat z-10 grayscale;
|
||||||
content: "";
|
content: "";
|
||||||
@ -176,7 +176,7 @@ onMounted(() => {
|
|||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
::v-deep .ant-menu-item-selected {
|
:deep(.ant-menu-item-selected) {
|
||||||
@apply bg-transparent relative;
|
@apply bg-transparent relative;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
|
@ -23,11 +23,11 @@ provide("history_table_data", { tableData, updateTableData, loading, updateLoadi
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h1 class="text-2xl font-extrabold mb-2">{{ $t('history.title') }}</h1>
|
<h1 class="text-2xl font-extrabold mb-2">{{ $t('history.title') }}</h1>
|
||||||
<div class="grid grid-cols-12 gap-2">
|
<div class="grid grid-cols-10 gap-2">
|
||||||
<div class="col-span-2 pe-5">
|
<div class="col-span-2 ">
|
||||||
<HistorySidebar />
|
<HistorySidebar />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-10 ">
|
<div class="col-span-8 ">
|
||||||
<HistorySearch />
|
<HistorySearch />
|
||||||
<HistoryTable />
|
<HistoryTable />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,26 +1,36 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import Collapse from "@/components/customUI/Collapse.vue";
|
|
||||||
import Checkbox from "@/components/customUI/Checkbox.vue";
|
import Checkbox from "@/components/customUI/Checkbox.vue";
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import useBuildingStore from "@/stores/useBuildingStore";
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
import useSearchParam from "@/hooks/useSearchParam";
|
import useSearchParam from "@/hooks/useSearchParam";
|
||||||
import { getHistorySideBar } from "@/apis/history";
|
import { getHistorySideBar } from "@/apis/history";
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from "vue-i18n";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { searchParams, changeParams } = useSearchParam();
|
const { searchParams, changeParams } = useSearchParam();
|
||||||
|
|
||||||
// const store = useBuildingStore();
|
|
||||||
const selectedBuilding = ref([]);
|
const selectedBuilding = ref([]);
|
||||||
const deviceData = ref([]);
|
const deviceData = ref([]);
|
||||||
|
|
||||||
const getDeviceData = async (sub_tag, renew) => {
|
const getDeviceData = async (sub_tag, renew) => {
|
||||||
const res = await getHistorySideBar(sub_tag);
|
const res = await getHistorySideBar(sub_tag);
|
||||||
deviceData.value = res.data.map((d) => ({
|
deviceData.value = res.data.map((building) => ({
|
||||||
...d,
|
building_tag: building.building_tag,
|
||||||
key: d.building_tag,
|
building_name: building.building_name,
|
||||||
|
floors: building.floor_list.map((floor) => ({
|
||||||
|
floor_tag: floor.device_floor_tag,
|
||||||
|
floor_name: floor.floor_name,
|
||||||
|
devices: floor.device_list.map((device) => ({
|
||||||
|
...device,
|
||||||
|
key: device.device_number,
|
||||||
|
})),
|
||||||
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
selectedBuilding.value = res.data.map((d) => d.building_tag);
|
selectedBuilding.value = res.data.map((d) => d.building_tag);
|
||||||
changeSelected([res.data[0]?.device_list[0]?.device_number], renew);
|
changeSelected(
|
||||||
|
[res.data[0]?.floor_list[0]?.device_list[0]?.device_number],
|
||||||
|
renew
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const sysIsExisted = (building_tag) => {
|
const sysIsExisted = (building_tag) => {
|
||||||
@ -54,7 +64,6 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 取得 checked 設備列表
|
|
||||||
const selectedDeviceNumber = computed(() => {
|
const selectedDeviceNumber = computed(() => {
|
||||||
return typeof searchParams.value.Device_list === "string"
|
return typeof searchParams.value.Device_list === "string"
|
||||||
? [searchParams.value.Device_list]
|
? [searchParams.value.Device_list]
|
||||||
@ -75,34 +84,66 @@ const isChecked = (device, checked) => {
|
|||||||
|
|
||||||
const checkedBuilding = computed(() => {
|
const checkedBuilding = computed(() => {
|
||||||
let selected = [];
|
let selected = [];
|
||||||
deviceData.value.forEach(({ building_tag, device_list }) => {
|
deviceData.value.forEach(({ building_tag, floors }) => {
|
||||||
|
let allDevices = [];
|
||||||
|
floors.forEach((floor) => {
|
||||||
|
allDevices = [...allDevices, ...floor.devices];
|
||||||
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
selectedDeviceNumber.value?.filter(
|
selectedDeviceNumber.value?.filter(
|
||||||
(d) => d.split("_")[1] === building_tag
|
(d) => d.split("_")[1] === building_tag
|
||||||
).length === device_list.length
|
).length === allDevices.length
|
||||||
) {
|
) {
|
||||||
selected.push(building_tag);
|
selected.push(building_tag);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return selected;
|
return selected;
|
||||||
});
|
});
|
||||||
|
|
||||||
const buildingCheck = (building_tag) => {
|
const buildingCheck = (building_tag) => {
|
||||||
|
const building = deviceData.value.find(
|
||||||
|
(d) => d.building_tag === building_tag
|
||||||
|
);
|
||||||
|
const allDevicesInBuilding = building.floors.flatMap((floor) =>
|
||||||
|
floor.devices.map((device) => device.device_number)
|
||||||
|
);
|
||||||
|
|
||||||
if (checkedBuilding.value?.includes(building_tag)) {
|
if (checkedBuilding.value?.includes(building_tag)) {
|
||||||
|
// 取消勾選該建築下的所有設備
|
||||||
changeSelected(
|
changeSelected(
|
||||||
selectedDeviceNumber.value.filter(
|
selectedDeviceNumber.value.filter(
|
||||||
(device_number) => device_number.split("_")[1] !== building_tag
|
(device_number) => !allDevicesInBuilding.includes(device_number)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
// 勾選該建築下的所有設備
|
||||||
changeSelected([
|
changeSelected([
|
||||||
...new Set(
|
...new Set([...selectedDeviceNumber.value, ...allDevicesInBuilding]),
|
||||||
[
|
]);
|
||||||
...selectedDeviceNumber.value,
|
}
|
||||||
...deviceData.value
|
};
|
||||||
.find((d) => d.building_tag === building_tag)
|
|
||||||
?.device_list.map(({ device_number }) => device_number),
|
const areAllDevicesCheckedInFloor = (devices) => {
|
||||||
].filter((d) => d !== "")
|
return devices.every((device) =>
|
||||||
),
|
selectedDeviceNumber.value.includes(device.device_number)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleFloorDevices = (devices) => {
|
||||||
|
const allChecked = areAllDevicesCheckedInFloor(devices);
|
||||||
|
|
||||||
|
if (allChecked) {
|
||||||
|
changeSelected(
|
||||||
|
selectedDeviceNumber.value.filter(
|
||||||
|
(device_number) =>
|
||||||
|
!devices.some((device) => device.device_number === device_number)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const deviceNumbers = devices.map((device) => device.device_number);
|
||||||
|
changeSelected([
|
||||||
|
...new Set([...selectedDeviceNumber.value, ...deviceNumbers]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -132,50 +173,68 @@ const changeSelected = (Device_list, renew = false) => {
|
|||||||
:icon="['fas', 'search']"
|
:icon="['fas', 'search']"
|
||||||
class="w-6 h-6 mr-2 text-info"
|
class="w-6 h-6 mr-2 text-info"
|
||||||
/>
|
/>
|
||||||
<input type="text" :placeholder="t('button.enter_text')"
|
<input
|
||||||
class="text-white bg-transparent w-full" />
|
type="text"
|
||||||
|
:placeholder="t('button.enter_text')"
|
||||||
|
class="text-white bg-transparent w-full"
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<template v-for="d in deviceData" :key="d.building_tag">
|
<ul class="menu text-lg">
|
||||||
<Collapse
|
<template v-for="building in deviceData" :key="building.building_tag">
|
||||||
:open="selectedBuilding.includes(d.building_tag)"
|
<li>
|
||||||
:data="
|
<details :open="selectedBuilding.includes(building.building_tag)">
|
||||||
d.device_list?.map((device) => ({
|
<summary>
|
||||||
...device,
|
<Checkbox
|
||||||
key: device.device_number,
|
:title="building.building_name"
|
||||||
}))
|
:checked="checkedBuilding.includes(building.building_tag)"
|
||||||
"
|
@click="() => buildingCheck(building.building_tag)"
|
||||||
:toggle="() => toggleSelectedBuilding(d.building_tag)"
|
/>
|
||||||
>
|
</summary>
|
||||||
<!-- :checked="selectedDeviceNumber.includes(data.device_number)" -->
|
<ul>
|
||||||
<template #collapseTitle>
|
<template v-for="floor in building.floors" :key="floor.floor_tag">
|
||||||
<Checkbox
|
<li>
|
||||||
:title="d.building_name"
|
<details open>
|
||||||
:checked="checkedBuilding.includes(d.building_tag)"
|
<summary>
|
||||||
:onClick="
|
<Checkbox
|
||||||
() => {
|
:title="floor.floor_name"
|
||||||
buildingCheck(d.building_tag);
|
:checked="areAllDevicesCheckedInFloor(floor.devices)"
|
||||||
}
|
@click="toggleFloorDevices(floor.devices)"
|
||||||
"
|
/>
|
||||||
/>
|
</summary>
|
||||||
</template>
|
<ul>
|
||||||
<template #collapseContent="{ data }">
|
<template
|
||||||
<span class="flex items-center text-xl">
|
v-for="device in floor.devices"
|
||||||
<Checkbox
|
:key="device.device_number"
|
||||||
:title="data.device_name"
|
>
|
||||||
:checked="selectedDeviceNumber.includes(data.device_number)"
|
<li class="flex items-start">
|
||||||
:onClick="
|
<Checkbox
|
||||||
() => {
|
:title="device.device_name"
|
||||||
isChecked(
|
:checked="
|
||||||
data.device_number,
|
selectedDeviceNumber.includes(
|
||||||
!selectedDeviceNumber.includes(data.device_number)
|
device.device_number
|
||||||
);
|
)
|
||||||
}
|
"
|
||||||
"
|
@click="
|
||||||
/>
|
() =>
|
||||||
</span>
|
isChecked(
|
||||||
</template>
|
device.device_number,
|
||||||
</Collapse>
|
!selectedDeviceNumber.includes(
|
||||||
</template>
|
device.device_number
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ const getFloors = async () => {
|
|||||||
let data = res.data.find(d => d.building_tag === store.selectedBuilding?.building_tag)
|
let data = res.data.find(d => d.building_tag === store.selectedBuilding?.building_tag)
|
||||||
data = [
|
data = [
|
||||||
{
|
{
|
||||||
title: "總覽",
|
title: "All",
|
||||||
key: "main",
|
key: "main",
|
||||||
active: route.params.floor_id ? false : true,
|
active: route.params.floor_id ? false : true,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user