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" 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>

View File

@ -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"

View File

@ -115,12 +115,12 @@ 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: "";
@ -132,7 +132,7 @@ onMounted(() => {
} }
} }
::v-deep .ant-menu-item-selected { :deep .ant-menu-item-selected {
@apply bg-transparent relative; @apply bg-transparent relative;
&::before { &::before {

View File

@ -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>

View File

@ -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>

View File

@ -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 === "main", active: route.params.floor_id === "main",
}, },