Merge branch 'main' into feature/system

This commit is contained in:
JouChun 2024-10-21 23:31:40 -04:00
commit 1cc2ab77fa
6 changed files with 131 additions and 72 deletions

View File

@ -9,7 +9,7 @@
href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.css"
/>
<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/ui/1.13.3/jquery-ui.js"></script>
<script type="text/javascript" src="/requirejs/config.js"></script>

View File

@ -25,14 +25,14 @@ onMounted(() => {
<div
tabindex="0"
role="button"
class="text-white ml-8 text-xl font-semiLight "
class="text-white ml-8 text-lg font-semiLight "
>
{{ store.selectedBuilding?.full_name }}
<font-awesome-icon :icon="['fas', 'angle-down']" class="ml-1"/>
</div>
<ul
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
class="text-white my-1 text-base"

View File

@ -115,12 +115,12 @@ onMounted(() => {
color: #93c0dc;
}
::v-deep .ant-menu-submenu-title:active {
:deep(.ant-menu-submenu-title:active) {
color: #35759d !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 {
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat z-10 grayscale;
content: "";
@ -132,7 +132,7 @@ onMounted(() => {
}
}
::v-deep .ant-menu-item-selected {
:deep .ant-menu-item-selected {
@apply bg-transparent relative;
&::before {

View File

@ -23,11 +23,11 @@ provide("history_table_data", { tableData, updateTableData, loading, updateLoadi
<template>
<h1 class="text-2xl font-extrabold mb-2">{{ $t('history.title') }}</h1>
<div class="grid grid-cols-12 gap-2">
<div class="col-span-2 pe-5">
<div class="grid grid-cols-10 gap-2">
<div class="col-span-2 ">
<HistorySidebar />
</div>
<div class="col-span-10 ">
<div class="col-span-8 ">
<HistorySearch />
<HistoryTable />
</div>

View File

@ -1,26 +1,36 @@
<script setup>
import Collapse from "@/components/customUI/Collapse.vue";
import Checkbox from "@/components/customUI/Checkbox.vue";
import { computed, ref, watch } from "vue";
import useBuildingStore from "@/stores/useBuildingStore";
import useSearchParam from "@/hooks/useSearchParam";
import { getHistorySideBar } from "@/apis/history";
import { useI18n } from 'vue-i18n';
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { searchParams, changeParams } = useSearchParam();
// const store = useBuildingStore();
const selectedBuilding = ref([]);
const deviceData = ref([]);
const getDeviceData = async (sub_tag, renew) => {
const res = await getHistorySideBar(sub_tag);
deviceData.value = res.data.map((d) => ({
...d,
key: d.building_tag,
deviceData.value = res.data.map((building) => ({
building_tag: building.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);
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) => {
@ -54,7 +64,6 @@ watch(
}
);
// checked
const selectedDeviceNumber = computed(() => {
return typeof searchParams.value.Device_list === "string"
? [searchParams.value.Device_list]
@ -75,34 +84,66 @@ const isChecked = (device, checked) => {
const checkedBuilding = computed(() => {
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 (
selectedDeviceNumber.value?.filter(
(d) => d.split("_")[1] === building_tag
).length === device_list.length
).length === allDevices.length
) {
selected.push(building_tag);
}
});
return selected;
});
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)) {
//
changeSelected(
selectedDeviceNumber.value.filter(
(device_number) => device_number.split("_")[1] !== building_tag
(device_number) => !allDevicesInBuilding.includes(device_number)
)
);
} else {
//
changeSelected([
...new Set(
[
...selectedDeviceNumber.value,
...deviceData.value
.find((d) => d.building_tag === building_tag)
?.device_list.map(({ device_number }) => device_number),
].filter((d) => d !== "")
),
...new Set([...selectedDeviceNumber.value, ...allDevicesInBuilding]),
]);
}
};
const areAllDevicesCheckedInFloor = (devices) => {
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']"
class="w-6 h-6 mr-2 text-info"
/>
<input type="text" :placeholder="t('button.enter_text')"
class="text-white bg-transparent w-full" />
<input
type="text"
:placeholder="t('button.enter_text')"
class="text-white bg-transparent w-full"
/>
</label>
<template v-for="d in deviceData" :key="d.building_tag">
<Collapse
:open="selectedBuilding.includes(d.building_tag)"
:data="
d.device_list?.map((device) => ({
...device,
key: device.device_number,
}))
"
:toggle="() => toggleSelectedBuilding(d.building_tag)"
>
<!-- :checked="selectedDeviceNumber.includes(data.device_number)" -->
<template #collapseTitle>
<Checkbox
:title="d.building_name"
:checked="checkedBuilding.includes(d.building_tag)"
:onClick="
() => {
buildingCheck(d.building_tag);
}
"
/>
</template>
<template #collapseContent="{ data }">
<span class="flex items-center text-xl">
<Checkbox
:title="data.device_name"
:checked="selectedDeviceNumber.includes(data.device_number)"
:onClick="
() => {
isChecked(
data.device_number,
!selectedDeviceNumber.includes(data.device_number)
);
}
"
/>
</span>
</template>
</Collapse>
</template>
<ul class="menu text-lg">
<template v-for="building in deviceData" :key="building.building_tag">
<li>
<details :open="selectedBuilding.includes(building.building_tag)">
<summary>
<Checkbox
:title="building.building_name"
:checked="checkedBuilding.includes(building.building_tag)"
@click="() => buildingCheck(building.building_tag)"
/>
</summary>
<ul>
<template v-for="floor in building.floors" :key="floor.floor_tag">
<li>
<details open>
<summary>
<Checkbox
:title="floor.floor_name"
:checked="areAllDevicesCheckedInFloor(floor.devices)"
@click="toggleFloorDevices(floor.devices)"
/>
</summary>
<ul>
<template
v-for="device in floor.devices"
:key="device.device_number"
>
<li class="flex items-start">
<Checkbox
:title="device.device_name"
:checked="
selectedDeviceNumber.includes(
device.device_number
)
"
@click="
() =>
isChecked(
device.device_number,
!selectedDeviceNumber.includes(
device.device_number
)
)
"
/>
</li>
</template>
</ul>
</details>
</li>
</template>
</ul>
</details>
</li>
</template>
</ul>
</div>
</template>

View File

@ -17,7 +17,7 @@ const getFloors = async () => {
let data = res.data.find(d => d.building_tag === store.selectedBuilding?.building_tag)
data = [
{
title: "總覽",
title: "All",
key: "main",
active: route.params.floor_id === "main",
},