Merge branch 'main' into feature/assetMgmt

This commit is contained in:
koko 2024-11-01 16:59:09 +08:00
commit b48717f091
37 changed files with 707 additions and 347 deletions

View File

@ -1,3 +1,3 @@
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
VITE_FORGE_BASEURL = "http://localhost:5173"
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"

View File

@ -1,3 +1,3 @@
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
VITE_FILE_API_BASEURL = "https://ibms-cvilux.production.mjmtech.com.tw"
VITE_FORGE_BASEURL = "http://202.39.218.221:8080/file/netzero"
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"

44
public/config.json Normal file
View File

@ -0,0 +1,44 @@
{
"heatmap": {
"temp": {
"range": [0, 50],
"color": ["#0023F5", "#FF1C05"],
"unit": "°C"
},
"humi": {
"range": [15, 95],
"color": ["#ADD8E6", "#00008B"],
"unit": "%"
},
"CO2": {
"range": [0, 5000],
"color": ["#FFDAB9", "#FF8C00"],
"unit": "ppm"
},
"CO": {
"range": [0, 1000],
"color": ["#FFFFE0", "#FFD700"],
"unit": "ppm"
},
"CH2O": {
"range": [0, 100],
"color": ["#90EE90", "#006400"],
"unit": "ppb"
},
"PM1": {
"range": [0, 20],
"color": ["#E6E6FA", "#800080"],
"unit": "µg/m³"
},
"PM2.5": {
"range": [0, 55],
"color": ["#FFB6C1", "#FF0000"],
"unit": "µg/m³"
},
"PM10": {
"range": [0, 150],
"color": ["#FFDDC1", "#FF1493"],
"unit": "µg/m³"
}
}
}

View File

@ -65,4 +65,16 @@
.btn-text-without-border {
@apply active:border-0 focus:border-0 focus-visible:border-0 active:outline-none focus:outline-none focus-visible:outline-none;
}
.btn-add {
@apply text-white border border-cyan-400 bg-cyan-400 hover:bg-[theme("colors.cyan.500")]
}
.btn-search {
@apply text-white border border-sky-400 bg-sky-400 hover:bg-[theme("colors.sky.500")]
}
.btn-export {
@apply text-white border border-emerald-400 bg-emerald-400 hover:bg-[theme("colors.emerald.500")]
}
}

View File

@ -5,24 +5,40 @@ import { twMerge } from "tailwind-merge";
const props = defineProps({
items: Array,
withLine: Boolean,
withBtnClass: { type: Boolean, default: false },
// this is for change active button
onclick: Function,
className: String
className: String,
});
</script>
<template>
<div class="flex flex-wrap text-white items-center">
<button v-for="item in items" :class="twMerge(
'btn my-1',
item.active ? 'btn-success' : 'btn-outline-success',
withLine ? 'line' : 'mx-2 first:ml-0 ',
className
)
" :disabled="item.disabled" :key="item.key" @click.stop.prevent="(e) => {
<button
v-for="item in items"
:class="
twMerge(
'btn my-1',
withBtnClass
? item.btn
: item.active
? 'btn-success'
: 'btn-outline-success',
withLine ? 'line' : 'mx-2 first:ml-0 ',
className
)
"
:disabled="item.disabled"
:key="item.key"
@click.stop.prevent="
(e) => {
item.onClick ? item.onClick(e, item) : onclick(e, item);
}
">
"
>
<span v-if="withBtnClass">
<font-awesome-icon :icon="['fas', item.icon]" class=" text-lg" />
</span>
<slot name="buttonContent" v-bind="{ record: item }">
{{ item.title }}
</slot>

View File

@ -161,7 +161,7 @@ watch(
<div :class="withStyle ? 'content-box' : 'py-5'">
<div class="content-decoration">
<slot name="beforeTable"></slot>
<form ref="form">
<form ref="form " class="overflow-x-auto">
<table
:class="
twMerge(
@ -322,14 +322,17 @@ watch(
<style lang="css" scoped>
/**資料框**/
.content-box {
@apply border border-info p-1 relative mb-4 bg-transparent;
@apply border border-info p-1 relative mb-4 bg-transparent ;
}
.content-box .table {
@apply rounded-none;
}
.table th,
.table th {
@apply bg-cyan-600 bg-opacity-30 border-r border-b border-white text-lg font-semibold text-white text-center px-2 py-3;
}
.table td {
@apply border-r border-b border-white text-lg font-semibold text-white text-center px-2 py-3;
}

View File

@ -16,6 +16,7 @@ import useSystemStatusByBaja from "@/hooks/baja/useSystemStatusByBaja";
import ForgeInfoModal from "../../views/system/components/SystemInfoModal.vue";
import useAlarmStore from "@/stores/useAlarmStore";
import useForgeSprite from "@/hooks/forge/useForgeSprite";
import useHeatmapBarStore from "@/stores/useHeatmapBarStore";
const props = defineProps({
initialData: Object,
@ -27,13 +28,9 @@ const props = defineProps({
},
},
});
const store = useHeatmapBarStore();
const heat_bar_isShow = ref(false);
const updateHeatBarIsShow = (isShow) => {
heat_bar_isShow.value = isShow;
};
const { updateDataVisualization, createSprites, hideAllObjects, forgeClickListener, clear } = useForgeSprite()
const { updateDataVisualization, createSprites, showSubSystemObjects, forgeClickListener, clear } = useForgeSprite()
const forgeDom = ref(null);
@ -92,9 +89,10 @@ const loadModel = (viewer, filePath) => {
});
};
// const loadModel = (viewer, urn) => {
// const loadModel = (viewer) => {
// return new Promise(function (resolve, reject) {
// async function onDocumentLoadSuccess(doc) {
// console.log("");
// viewer.setGroundShadow(false);
// viewer.impl.renderer().setClearAlpha(0); //clear alpha channel
// viewer.impl.glrenderer().setClearColor(0xffffff, 0); //set transparent background, color code does not matter
@ -163,7 +161,7 @@ const initForge = async () => {
viewer.isLoadDone()
);
hideAllObjects();
showSubSystemObjects();
createSprites();
forgeClickListener();
})
@ -201,22 +199,18 @@ onUnmounted(() => {
<template>
<ForgeInfoModal :data="currentInfoModalData" />
<div id="forge-preview" ref="forgeDom" class="relative w-full h-full min-h-full">
<div v-show="heat_bar_isShow" class="absolute z-10 heatbar">
<div v-show="store.heat_bar_isShow" class="absolute z-10 heatbar">
<div class="w-40 flex justify-between text-[10px] mb-1">
<span class="text-gradient-1">10 °C</span>
<span class="text-gradient-2">20 °C</span>
<span class="text-gradient-3">30 °C</span>
<span class="text-gradient-4">40 °C</span>
<span v-for="value in store.heatmapConfig?.range" class="text-gradient-1">{{ value }} {{
store.heatmapConfig?.unit }}</span>
</div>
<div class="w-40 h-3" style="
background: linear-gradient(
<div class="w-40 h-3" :style="{
background: `linear-gradient(
to right,
#0000ff 0%,
#00ff00 33%,
#ffff00 66%,
#ff0000 100%
);
"></div>
${store.heatmapConfig?.color[0]} 0%,
${store.heatmapConfig?.color[1]} 100%
)`
}"></div>
</div>
<!-- label -->
<!-- https://github.com/augustogoncalves/forge-plant-operation/blob/master/forgeSample/wwwroot/js/iconExtension.js -->
@ -264,11 +258,11 @@ onUnmounted(() => {
}
.homeViewWrapper {
transform: scale(0.9) !important;
transform: scale(2) !important;
}
.heatbar {
right: v-bind("`${props.cubeStyle.right + 2}%`") !important;
/* right: v-bind("`${props.cubeStyle.right + 2}%`") !important; */
top: 0% !important;
}
</style>

View File

@ -5,10 +5,13 @@ import { getAuth, getAllSysSidebar } from "@/apis/building";
import useBuildingStore from "@/stores/useBuildingStore";
import useUserInfoStore from "@/stores/useUserInfoStore";
import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router";
import { twMerge } from "tailwind-merge";
const { locale } = useI18n();
const store = useUserInfoStore();
const buildingStore = useBuildingStore();
const route = useRoute();
const openKeys = ref([]); //
const iniFroList = async () => {
@ -18,9 +21,9 @@ const iniFroList = async () => {
res.data.map((d) =>
AUTHPAGES.find(({ authCode }) => authCode === d.authCode)
? {
...d,
...AUTHPAGES.find(({ authCode }) => authCode === d.authCode),
}
...d,
...AUTHPAGES.find(({ authCode }) => authCode === d.authCode),
}
: d
)
);
@ -71,38 +74,93 @@ onMounted(() => {
<template>
<ul class="px-1 menu-box my-2">
<li class="flex flex-col items-center justify-center">
<router-link :to="{ name: 'dashboard' }" class="flex flex-col justify-center items-center btn-group text-white">
<font-awesome-icon :icon="['fas', 'home']" size="2x" class="w-10 m-auto" />
<router-link
:to="{ name: 'dashboard' }"
class="flex flex-col justify-center items-center btn-group text-white"
>
<font-awesome-icon
:icon="['fas', 'home']"
size="2x"
class="w-10 m-auto"
/>
{{ $t("home") }}
</router-link>
</li>
<li v-for="page in authPages" class="flex flex-col items-center justify-center">
<a v-if="page.authCode === 'PF1'" @click="showDrawer"
class="flex flex-col justify-center items-center btn-group text-white cursor-pointer">
<font-awesome-icon :icon="['fas', page.icon]" size="2x" class="w-10 m-auto" />
<li
v-for="page in authPages"
class="flex flex-col items-center justify-center"
>
<a
v-if="page.authCode === 'PF1'"
@click="showDrawer"
:class="
twMerge(
'flex flex-col justify-center items-center btn-group text-white cursor-pointer',
route.fullPath.includes('/system')
? 'router-link-active router-link-exact-active'
: ''
)
"
>
<font-awesome-icon
:icon="['fas', page.icon]"
size="2x"
class="w-10 m-auto"
/>
{{ page.subName }}
</a>
<router-link v-else :to="page.navigate" type="link"
class="flex flex-col justify-center items-center btn-group text-white">
<font-awesome-icon :icon="['fas', page.icon]" size="2x" class="w-10 m-auto" />
<router-link
v-else
:to="page.navigate"
type="link"
class="flex flex-col justify-center items-center btn-group text-white"
>
<font-awesome-icon
:icon="['fas', page.icon]"
size="2x"
class="w-10 m-auto"
/>
{{ page.subName }}
</router-link>
</li>
</ul>
<a-drawer :width="250" placement="left" :open="open" :closable="false" @close="onClose" class="sub-drawer"
:maskStyle="{ opacity: 0 }" :bodyStyle="{ paddingLeft: 0, paddingRight: 0 }">
<a-menu mode="inline" theme="dark" class="text-lg bg-transparent" :openKeys="openKeys"
@openChange="handleOpenChange">
<a-sub-menu v-for="main in buildingStore.mainSubSys" :key="main.main_system_tag" :title="main.full_name">
<a-menu-item v-for="sub in main.history_Sub_systems" :key="sub.sub_system_tag" @click="() => onClose()">
<router-link :to="{
name: 'sub_system',
params: {
main_system_id: main.main_system_tag,
sub_system_id: sub.sub_system_tag,
floor_id: 'main'
},
}">
<a-drawer
:width="250"
placement="left"
:open="open"
:closable="false"
@close="onClose"
class="sub-drawer"
:maskStyle="{ opacity: 0 }"
:bodyStyle="{ paddingLeft: 0, paddingRight: 0 }"
>
<a-menu
mode="inline"
theme="dark"
class="text-lg bg-transparent"
:openKeys="openKeys"
@openChange="handleOpenChange"
>
<a-sub-menu
v-for="main in buildingStore.mainSubSys"
:key="main.main_system_tag"
:title="main.full_name"
>
<a-menu-item
v-for="sub in main.history_Sub_systems"
:key="sub.sub_system_tag"
@click="() => onClose()"
>
<router-link
:to="{
name: 'sub_system',
params: {
main_system_id: main.main_system_tag,
sub_system_id: sub.sub_system_tag,
floor_id: 'main',
},
}"
>
{{ sub.full_name }}
</router-link>
</a-menu-item>
@ -115,28 +173,17 @@ onMounted(() => {
color: #93c0dc;
}
:deep(.ant-menu-submenu-title:active) {
color: #35759d !important;
background-color: transparent !important;
}
: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: "";
background: url(@ASSET/img/chart-data-background03.svg) center center;
}
&:active {
background-color: transparent !important;
:deep(.ant-menu-submenu-selected) {
.ant-menu-submenu-title {
@apply text-info;
}
}
:deep .ant-menu-item-selected {
:deep(.ant-menu-item-selected) {
@apply bg-transparent relative;
&::before {
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat z-10;
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat saturate-200 z-10;
content: "";
background: url(@ASSET/img/chart-data-background03.svg) center center;
}
@ -146,7 +193,7 @@ onMounted(() => {
}
a {
color: #89d2ff !important;
color: #35ecec !important;
text-shadow: 0px 0px 1px #fff;
}
}

View File

@ -180,7 +180,8 @@
"new_category": "新类别",
"index": "编号",
"oriOrgName": "档案",
"operation": "功能"
"operation": "功能",
"upload": "图资上传"
},
"assetManagement": {
"title": "资产管理",

View File

@ -180,7 +180,8 @@
"new_category": "新類別",
"index": "編號",
"oriOrgName": "檔案",
"operation": "功能"
"operation": "功能",
"upload": "圖資上傳"
},
"assetManagement": {
"title": "資產管理",

View File

@ -22,9 +22,9 @@
"category": "Category",
"value": "Value",
"date": "Record Time",
"point": "Point",
"point": "Character",
"combinations": "Common combinations",
"date_range": "Date range",
"date_range": "Date Range",
"time_range": "Time interval",
"start_date": "Start date",
"start_time": "Start time",
@ -73,26 +73,26 @@
"confirm": "Confirm"
},
"alert": {
"query_title": "Alarm record query",
"setting_title": "Alarm settings",
"offnormal": "off normal",
"normal": "normal",
"unacked": "unacked",
"acked": "acked",
"30days": "Last 30 days",
"start_date": "Start date",
"end_date": "End date",
"building_and_floor": "Building - floor",
"query_title": "Alarm Record Query",
"setting_title": "Alarm Settings",
"offnormal": "Off Normal",
"normal": "Normal",
"unacked": "Unacked",
"acked": "Acked",
"30days": "Last 30 Days",
"start_date": "Start Date",
"end_date": "End Date",
"building_and_floor": "Building - Floor",
"uuid": "Exception ID",
"alarmClass": "Exception Category",
"device_name": "Device name",
"device_number": "Device number",
"date": "Occurrence date",
"time": "Occurrence time",
"error_msg": "Abnormal cause",
"device_name": "Device Name",
"device_number": "Device Number",
"date": "Occurrence Date",
"time": "Occurrence Time",
"error_msg": "Abnormal Cause",
"ack_state": "Ack Confirm",
"repair_order_number": "Repair order number",
"repair_order": "Repair order",
"repair_order_number": "Repair Order Number",
"repair_order": "Repair Order",
"form_number": "Form Number",
"start_time": "Estimated Start Time",
"item": "Item",
@ -102,59 +102,59 @@
"repair_item_code": "Repair Item Code (Device Number)",
"responsible_vendor": "Responsible Vendor",
"status": "Status",
"not_completed": "Not completed",
"not_completed": "Not Completed",
"completed": "Completed",
"worker_id": "Worker ID",
"notice": "Notice",
"result_description": "Result Description",
"upload_file": "Upload File",
"enable": "Enable",
"not_enabled": "Not enabled",
"not_enabled": "Not Enabled",
"qualifications": "Qualifications",
"upper_limit": "Upper limit",
"lower_limit": "Lower limit",
"highDelay": "Max duration (s)",
"lowDelay": "Min duration (s)",
"warning_method": "Warning method",
"warning_time": "Warning time",
"upper_limit": "Upper Limit",
"lower_limit": "Lower Limit",
"highDelay": "Max Duration (s)",
"lowDelay": "Min Duration (s)",
"warning_method": "Warning Method",
"warning_time": "Warning Time",
"operation": "Function",
"alarm_settings": "Abnormal alarm settings",
"time_setting": "Time setting",
"yes": "yes",
"no": "no",
"no_notify": "No notification",
"alarm_settings": "Abnormal Alarm Settings",
"time_setting": "Time Setting",
"yes": "Yes",
"no": "No",
"no_notify": "No Notification",
"notify_name": "Name",
"notify_phone": "Phone number",
"notify_email": "email",
"notify_items": "Notification items",
"notify_list": "Notification list",
"choose": "choose"
"notify_phone": "Phone Number",
"notify_email": "Email",
"notify_items": "Notification Items",
"notify_list": "Notification List",
"choose": "Choose"
},
"operation": {
"title": "Operation and maintenance management",
"title": "Operation And Maintenance Management",
"project": "Project",
"location": "Location",
"uuid": "Exception ID",
"form_number": "Form Number",
"device_name": "Device name",
"device_name": "Device Name",
"status": "Status",
"staff": "Staff",
"start_time": "Estimated start time",
"upload": "File upload",
"finish_time": "Completion time",
"start_time": "Estimated Start Time",
"upload": "File Upload",
"finish_time": "Completion Time",
"operation": "Function",
"vendor": "company",
"contact_person": "Contact person",
"vendor": "Company",
"contact_person": "Contact Person",
"phone": "Phone",
"email": "email",
"created_at": "Creation date",
"maintainance": "Maintainance",
"email": "Email",
"created_at": "Creation Date",
"maintenance": "Maintenance",
"repair": "Repair",
"company_info": "Company Info",
"repair_item": "Repair Item",
"repair_item_code": "Repair Item Code (Device Number)",
"responsible_vendor": "Responsible Vendor",
"not_completed": "Not completed",
"not_completed": "Not Completed",
"completed": "Completed",
"worker_id": "Worker ID",
"notice": "Notice",
@ -163,36 +163,37 @@
"name": "Name",
"city": "City",
"address": "Address",
"tax_id_number": "tax ID number",
"tax_id_number": "Tax ID Number",
"remark": "Remark",
"date": "Date",
"serial": "Order number",
"serial": "Order Number",
"today": "Today",
"yesterday": "Yesterday",
"start_created_at": "Start date",
"end_created_at": "End date",
"start_created_at": "Start Date",
"end_created_at": "End Date",
"enter_text": "Please enter text",
"enter_serial": "Please enter the order number"
},
"graphManagement": {
"title": "Data and Publication Management",
"title": "Data And Publication Management",
"category": "Category",
"new_category": "New category",
"index": "serial number",
"oriOrgName": "file",
"operation": "Function"
"new_category": "New Category",
"index": "Serial Number",
"oriOrgName": "File",
"operation": "Function",
"upload": "Upload"
},
"assetManagement": {
"title": "Asset Management",
"add_category": "Add category",
"add_category": "Add Category",
"system_name": "Name",
"system_value": "Code",
"system_parent": "Category",
"device_number": "Device number",
"device_name": "Device name",
"asset_number": "Asset number",
"device_number": "Device Number",
"device_name": "Device Name",
"asset_number": "Asset Number",
"floor": "Location",
"add_floor": "Add floor",
"add_floor": "Add Floor",
"add_floor_text": "Floor map must be uploaded first",
"device_coordinate": "Coordinate",
"brand_and_modal": "Brand/Model",
@ -200,44 +201,44 @@
"modal": "Model",
"company_and_contact": "Company/Contact Person",
"company": "Company",
"buying_date": "Purchase time",
"oriFile": "File upload",
"created_at": "Creation time",
"buying_date": "Purchase Time",
"oriFile": "File Upload",
"created_at": "Creation Time",
"operation": "Function",
"device_list": "Device list",
"edit_device": "Edit device",
"add_device": "Add device",
"device_list": "Device List",
"edit_device": "Edit Device",
"add_device": "Add Device",
"operate_text": "Display name",
"fill_text": "Please fill it in by system personnel",
"equipment_point": "Equipment point",
"equipment_point": "Equipment Point",
"point": "Point",
"add_sensor": "Add new sensor",
"associated_device": "Associated devices",
"add_sensor": "Add New Sensor",
"associated_device": "Associated Devices",
"choose": "Choose",
"index": "serial number",
"floor_plan": "Floor plan"
"index": "Serial Number",
"floor_plan": "Floor Plan"
},
"accountManagement": {
"account_title": "Account Management",
"role_title": "Role Management",
"index": "serial number",
"index": "Serial Number",
"name": "Name",
"account": "Account",
"password": "Password",
"role": "Role",
"role_name": "Role name",
"role_permissions": "Role permissions",
"role_permissions_setting": "Role permissions settings",
"permission_name": "Permission name",
"basic_permissions": "Basic permissions",
"production_permissions": "Production setting permissions",
"email": "email",
"role_name": "Role Name",
"role_permissions": "Role Permissions",
"role_permissions_setting": "Role Permissions Settings",
"permission_name": "Permission Name",
"basic_permissions": "Basic Ppermissions",
"production_permissions": "Production Setting Permissions",
"email": "Email",
"phone": "Phone",
"created_at": "Created time",
"created_at": "Created Time",
"operation": "Function",
"name_placeholder": "Please enter user name",
"role_placeholder": "Please enter the role name",
"change_password": "Change password",
"change_password": "Change Password",
"choose": "Choose"
},
"button": {

View File

@ -56,7 +56,8 @@ import {
faWind,
faEye,
faEyeSlash,
faGlobe
faGlobe,
faDownload
} from "@fortawesome/free-solid-svg-icons";
/* add icons to the library */
@ -114,7 +115,8 @@ library.add(
faWind,
faEye,
faEyeSlash,
faGlobe
faGlobe,
faDownload
);
export default library;

View File

@ -1,70 +1,112 @@
import useSelectedFloor from "@/hooks/useSelectedFloor";
import { watch, ref, inject } from "vue";
import { useRoute } from "vue-router";
function useForgeFloor() {
const findLevels = (viewer) => {
return new Promise((resolve, reject) => {
viewer.model.search(
"layer",
(nodeIds) => {
let levels = [];
const tree = viewer.model.getInstanceTree();
for (let i = 0; i < nodeIds.length; i++) {
const dbId = nodeIds[i];
const name = tree.getNodeName(dbId);
if (!name || name.includes("<沒有層級>")) continue;
levels.push({
guid: dbId,
name,
dbId,
extension: {
buildingStory: true,
structure: false,
computationHeight: 0,
groundPlane: false,
hasAssociatedViewPlans: false,
},
});
}
levels = levels.sort((a, b) => b.elevation - a.elevation);
resolve(levels);
},
(e) => {
reject(e);
}
);
});
const route = useRoute();
const levelList = ref([]);
const { selectedFloor } = useSelectedFloor();
const { subscribeData } = inject("system_deviceList");
const forgeViewer = ref(null);
const dataVizExtn = ref(null);
const updateViewerFloor = (viewer, dataVisualization) => {
forgeViewer.value = viewer;
dataVizExtn.value = dataVisualization;
};
// function getCutPlaneParam(idx, n, viewer, levels) {
// if (idx < 0 || !n) return;
const findLevels = () => {
forgeViewer.value.model.search(
"layer",
(nodeIds) => {
let levels = [];
const tree = forgeViewer.value.model.getInstanceTree();
for (let i = 0; i < nodeIds.length; i++) {
const dbId = nodeIds[i];
const name = tree.getNodeName(dbId);
if (!name || name.includes("<沒有層級>")) continue;
levels.push({
guid: dbId,
name,
dbId,
extension: {
buildingStory: true,
structure: false,
computationHeight: 0,
groundPlane: false,
hasAssociatedViewPlans: false,
},
});
}
levels = levels.sort((a, b) => b.elevation - a.elevation);
console.log(levels);
levelList.value = levels;
},
(e) => {
console.log(e);
}
);
};
// const level = levels[idx];
// if (!level) return;
watch(forgeViewer, () => {
findLevels();
});
// const model = viewer.model;
// const globalOffset = model.getData().globalOffset;
// const units = model.getUnitString();
// const elevRaw = Autodesk.Viewing.Private.convertUnits(
// "ft",
// units,
// 1,
// level.elevation
// );
// let d = elevRaw - globalOffset.z - 0.5;
// if (n == 1) d = -1 * d;
const hideDbIdFn = () => {
const tree = forgeViewer.value?.model.getInstanceTree();
const allDbIdsStr = Object.keys(tree.nodeAccess.dbIdToIndex);
for (var i = 0; i < allDbIdsStr.length; i++) {
forgeViewer.value.hide(parseInt(allDbIdsStr[i]));
}
};
const showDbIdFn = () => {
hideDbIdFn();
subscribeData.value.forEach((value, index) => {
forgeViewer.value.show(value.forge_dbid);
});
// return new THREE.Vector4(0, 0, n, d);
// }
forgeViewer.value.impl.invalidate(true);
};
// function profile(viewer, levels) {
// //const upperIdx = 6;
// const upperCutPlaneParam = getCutPlaneParam(2, 1, viewer, levels);
// //const lowerIdx = 7;
// const lowerCutPlaneParam = getCutPlaneParam(3, -1, viewer, levels);
// viewer.setCutPlanes([upperCutPlaneParam, lowerCutPlaneParam]);
// }
const showLevels = () => {
if (forgeViewer.value) {
const currentFloorName =
selectedFloor.value?.title?.replaceAll(/U/gi, "") || "";
const level = levelList.value.find(({ name }) =>
name.includes(currentFloorName)
);
console.log(currentFloorName, level);
if (!level) {
forgeViewer.value?.impl.toggleGhosting(true);
forgeViewer.value?.fitToView([forgeViewer.value.model.getRootId()]);
showDbIdFn();
} else {
hideDbIdFn();
// forgeViewer.value.clearSelection();
// forgeViewer.value.model.setAllVisibility(0);
forgeViewer.value.impl.toggleGhosting(false);
// forgeViewer.value.impl.toggleGroundShadow(false);
forgeViewer.value.show(level.dbId);
forgeViewer.value.impl.invalidate(true);
forgeViewer.value.fitToView([level.dbId]);
}
}
};
return { findLevels, profile };
watch(
() => route,
(newValue) => {
console.log(newValue);
newValue && showLevels();
},
{
deep: true,
}
);
return { findLevels, showLevels, updateViewerFloor };
}
export default useForgeFloor;

View File

@ -1,49 +1,141 @@
import { watch, inject, markRaw, ref } from "vue";
import { watch, inject, markRaw, ref, computed, onMounted } from "vue";
import { useRoute } from "vue-router";
import useHeatmapBarStore from "@/stores/useHeatmapBarStore";
import useSystemShowData from "@/hooks/useSystemShowData";
export default function useForgeHeatmap(dataVizExtn, forgeViewer){
const { subscribeData } = inject("system_deviceList");
export default function useForgeHeatmap() {
const route = useRoute();
const { subscribeData, realtimeData } = inject("system_deviceList");
const createHeatMap = async (heatMapName) => {
const store = useHeatmapBarStore();
const forgeViewer = ref(null);
const dataVizExtn = ref(null);
const updateViewExtension = (viewer, dataVisualization) => {
forgeViewer.value = viewer;
dataVizExtn.value = dataVisualization;
};
//create the heatmap
function getSensorValue(device, sensorType, pointData) {
const dev = realtimeData.value.find(
({ device_number }) => device_number === device.id
);
if (dev) {
const [min, max] = store.heatmapConfig?.range;
const point = dev.data.find(({ point }) => point === route.query?.gas);
console.log(9, device, dev, point, (point?.value - min || 0) / max);
return Math.random();
}
return 0;
}
const { flatSubData } = useSystemShowData();
const data = computed(() =>
flatSubData.value?.map((d) => ({
...d,
...Object.fromEntries(
d.points.map(({ point, value }) => [point, 0]) || []
),
}))
);
watch(
() => realtimeData,
() => {
dataVizExtn.value &&
Object.keys(dataVizExtn.value?.surfaceShading)?.length &&
dataVizExtn.value.updateSurfaceShading(getSensorValue);
},
{
deep: true,
}
);
const createHeatMap = async () => {
if (!dataVizExtn.value) return;
const heatMapName = `iot_heatmap_${route.query?.gas}`;
console.log("createHeatMap", heatMapName);
const {
SurfaceShadingData,
SurfaceShadingPoint,
SurfaceShadingNode,
SurfaceShadingGroup,
} = Autodesk.DataVisualization.Core;
const shadingGroup = new SurfaceShadingGroup(`iot_heatmap_${heatMapName}`);
const shadingGroup = new SurfaceShadingGroup(`${heatMapName}`);
const rooms = new Map();
for (const { id, roomDbId, position, sensorTypes } of subscribeData.value) {
if (!id || roomDbId == -1 || !roomDbId) {
continue;
}
const roomSet = new Set(data.value.map(({ room_dbid }) => room_dbid));
if (!rooms.has(roomDbId)) {
const room = new SurfaceShadingNode(id, roomDbId);
shadingGroup.addChild(room);
rooms.set(roomDbId, room);
// 每個room是一個node
[...roomSet].forEach((roomDbId) => {
if (!roomDbId) {
return;
}
const room = rooms.get(roomDbId);
room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes));
}
const room = new SurfaceShadingNode(`room_${roomDbId}`, roomDbId);
const shadingData = new SurfaceShadingData();
//相同room內的設備
data.value
.filter(({ room_dbid }) => room_dbid === roomDbId)
.forEach(
({
device_number: id,
device_coordinate_3d: position,
sensorTypes,
}) =>
room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes))
);
shadingGroup.addChild(room);
});
// data.value.forEach(
// ({
// device_number: id,
// room_dbid: roomDbId,
// device_coordinate_3d: position,
// sensorTypes,
// }) => {
// if (!id || roomDbId == -1 || !roomDbId) {
// return;
// }
// if (!rooms.has(roomDbId)) {
// const room = new SurfaceShadingNode(id, roomDbId);
// shadingGroup.addChild(room);
// rooms.set(roomDbId, room);
// }
// const room = rooms.get(roomDbId);
// room.addPoint(new SurfaceShadingPoint(id, position, route.query.gas));
// }
// );
const shadingData = new SurfaceShadingData(`${heatMapName}`);
shadingData.addChild(shadingGroup);
shadingData.initialize(forgeViewer.value?.model);
await dataVizExtn.value.setupSurfaceShading(
forgeViewer.value.model,
shadingData
);
dataVizExtn.value.registerSurfaceShadingColors(
heatMapName,
[0x0000ff, 0x00ff00, 0xffff00, 0xff0000]
route.query?.gas,
store.heatmapConfig?.color
);
dataVizExtn.value.renderSurfaceShading(
`iot_heatmap_${heatMapName}`,
heatMapName,
route.query?.gas,
getSensorValue
);
};
}
watch(
data,
(newValue, oldValue) => {
dataVizExtn.value?.removeSurfaceShading();
createHeatMap(route.query.gas);
},
{ deep: true }
);
return { createHeatMap, updateViewExtension };
}

View File

@ -1,17 +1,21 @@
import { watch, inject, markRaw, ref, computed } from "vue";
import { watch, inject, markRaw, ref, computed, provide } from "vue";
import useAlarmStore from "@/stores/useAlarmStore";
import hexToRgb from "@/util/hexToRgb";
import { useRoute } from "vue-router";
import useSelectedFloor from "@/hooks/useSelectedFloor";
import useSystemShowData from "@/hooks/useSystemShowData"
import useForgeHeatmap from "./useForgeHeatmap";
import useForgeFloor from "./useForgeFloor";
export default function useForgeSprite() {
const store = useAlarmStore();
const { subscribeData } = inject("system_deviceList");
const { getCurrentInfoModalData, clearSelectedDeviceInfo } = inject(
"system_selectedDevice"
);
const forgeViewer = ref(null);
const dataVizExtn = ref(null);
const { createHeatMap, updateViewExtension } = useForgeHeatmap();
const { updateViewerFloor } = useForgeFloor();
const updateDataVisualization = async (viewer) => {
if (!forgeViewer.value) {
forgeViewer.value = markRaw(viewer);
@ -21,6 +25,8 @@ export default function useForgeSprite() {
"Autodesk.DataVisualization"
);
dataVizExtn.value = markRaw(dataVisualization);
updateViewExtension(markRaw(viewer), markRaw(dataVisualization));
updateViewerFloor(markRaw(viewer), markRaw(dataVisualization))
};
function onSpriteClicked(event) {
@ -45,14 +51,7 @@ export default function useForgeSprite() {
}
}
const { selectedFloor } = useSelectedFloor();
const showData = computed(() =>
selectedFloor.value?.key === "main"
? subscribeData.value
: subscribeData.value.filter(
({ floor_guid }) => floor_guid === selectedFloor.value?.key
) || []
);
const { flatSubData } = useSystemShowData()
// 創建 sprites
const createSprites = async () => {
@ -70,9 +69,8 @@ export default function useForgeSprite() {
);
const viewableData = new DataVizCore.ViewableData();
viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels
showData.value?.forEach((d, index) => {
flatSubData.value?.forEach((d, index) => {
if (d.device_coordinate_3d) {
console.log(d.device_coordinate_3d);
const position = d.device_coordinate_3d;
style.color = new THREE.Color(hexToRgb(d.device_normal_color));
const viewable = new DataVizCore.SpriteViewable(
@ -89,6 +87,7 @@ export default function useForgeSprite() {
viewableData.finish().then(
() => {
dataVizExtn.value.addViewables(viewableData);
createHeatMap();
},
(error) => {
console.log(error);
@ -98,9 +97,12 @@ export default function useForgeSprite() {
};
watch(
() => showData,
() => flatSubData,
() => {
forgeViewer.value?.isLoadDone() && createSprites();
if (forgeViewer.value?.isLoadDone()) {
createSprites();
showSubSystemObjects();
}
},
{
deep: true,
@ -146,7 +148,10 @@ export default function useForgeSprite() {
for (var i = 0; i < allDbIdsStr.length; i++) {
forgeViewer.value.hide(parseInt(allDbIdsStr[i]));
}
};
const showSubSystemObjects = () => {
hideAllObjects();
subscribeData.value.forEach((value, index) => {
forgeViewer.value.show(value.forge_dbid);
});
@ -166,11 +171,13 @@ export default function useForgeSprite() {
forgeViewer.value.tearDown();
};
return {
createSprites,
updateDataVisualization,
hideAllObjects,
showSubSystemObjects,
forgeClickListener,
clear
clear,
};
}

View File

@ -0,0 +1,27 @@
import useSelectedFloor from "@/hooks/useSelectedFloor";
import { computed, inject, watch } from "vue";
function useSystemShowData() {
const { data } = inject("system_deviceList");
const { selectedFloor } = useSelectedFloor();
const showData = computed(() =>
selectedFloor.value?.key === "main"
? data.value
: data.value.filter(
({ floor_guid }) => floor_guid === selectedFloor.value?.key
) || []
);
const flatSubData = computed(() => {
let items = [];
showData.value.forEach((device) => {
items = [...items, ...device.device_list];
});
return items;
});
return { showData, flatSubData };
}
export default useSystemShowData;

View File

@ -0,0 +1,31 @@
import { defineStore } from "pinia";
import axios from "axios";
import { useRoute } from "vue-router";
import { computed, ref, onMounted } from "vue";
const useHeatmapBarStore = defineStore("heatmap", () => {
const route = useRoute();
const allHeatMaps = ref({});
const heatmapConfig = computed(() => allHeatMaps.value[route.query?.gas]);
const getConfig = async () => {
const api =
import.meta.env.MODE === "production"
? "/dist/config.json"
: "/config.json";
const res = await axios.get(api);
console.log(res);
allHeatMaps.value = res.data.heatmap;
};
onMounted(() => {
getConfig();
});
const heat_bar_isShow = computed(() => Boolean(heatmapConfig.value));
return { heatmapConfig, heat_bar_isShow };
});
export default useHeatmapBarStore;

View File

@ -102,7 +102,7 @@ const closeModal = () => {
</script>
<template>
<button class="btn btn-sm btn-success mr-3" @click.stop.prevent="openModal">
<button class="btn btn-sm btn-add mr-3" @click.stop.prevent="openModal">
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
</button>
<Modal

View File

@ -194,9 +194,10 @@ const openCompanyAddModal = () => {
<OperationTableModal type="asset" />
<button
type="button"
class="btn btn-success btn-sm ml-2 mt-7"
class="btn btn-add ml-2 mt-7"
@click="openCompanyAddModal"
>
<font-awesome-icon :icon="['fas', 'plus']" />
{{ $t("button.add") }}
</button>
</div>

View File

@ -192,9 +192,10 @@ const deleteItem = (value) => {
</span>
<button
type="button"
class="btn btn-sm btn-success"
class="btn btn-sm btn-add"
@click.stop.prevent="openModal"
>
<font-awesome-icon :icon="['fas', 'plus']" />
{{ $t("assetManagement.add_sensor") }}
</button>
</div>

View File

@ -142,13 +142,6 @@ const removeAccount = async (id) => {
<AccountPasswordModal :reset="resetModalForm" :account="formState" />
<Table :columns="columns" :dataSource="dataSource" :loading="loading">
<template #beforeTable>
<button
class="btn btn-success mr-3"
@click.stop.prevent="() => openModal(null)"
>
<font-awesome-icon :icon="['fas', 'plus']" />
{{ $t("button.add") }}
</button>
<div class="flex items-center mb-8">
<Input
:placeholder="t('accountManagement.name_placeholder')"
@ -161,18 +154,21 @@ const removeAccount = async (id) => {
name="Role_full_name"
:value="searchData"
/>
<button
class="btn btn-outline-success ml-5"
@click.stop.prevent="onSearch"
>
<button class="btn btn-search ml-5" @click.stop.prevent="onSearch">
<font-awesome-icon :icon="['fas', 'search']" />
{{ $t("button.search") }}
</button>
<button
class="btn btn-outline-success mx-4"
@click.stop.prevent="onReset"
>
<button class="btn btn-neutral mx-4" @click.stop.prevent="onReset">
{{ $t("button.reset") }}
</button>
<button
class="btn btn-add ml-10"
@click.stop.prevent="() => openModal(null)"
>
<font-awesome-icon :icon="['fas', 'plus']" />
{{ $t("button.add") }}
</button>
</div>
</template>
<template #bodyCell="{ record, column, index }">

View File

@ -102,13 +102,11 @@ const onSearch = () => {
name="Full_name"
:value="searchRole"
/>
<button
class="btn btn-outline-info mx-3"
@click.stop.prevent="onSearch"
>
<button class="btn btn-search mx-3" @click.stop.prevent="onSearch">
<font-awesome-icon :icon="['fas', 'search']" />
{{ $t("button.search") }}
</button>
<button class="btn btn-success ml-10" @click.stop.prevent="add">
<button class="btn btn-add ml-10" @click.stop.prevent="add">
<font-awesome-icon :icon="['fas', 'plus']" /> {{ $t("button.add") }}
</button>
</div>

View File

@ -15,7 +15,10 @@ const { search } = inject("alert_table");
<AlertSearchNormalBtns />
<AlertSearchAckBtns />
<AlertSearchTimeRange />
<button class="btn btn-success ml-8" @click.stop.prevent="search">{{ $t("button.query")}}</button>
<button class="btn btn-search ml-8" @click.stop.prevent="search">
<font-awesome-icon :icon="['fas', 'search']" class=" text-lg" />
{{ $t("button.search")}}
</button>
</div>
<div class="w-full flex flex-wrap items-center justify-start">
<AlertSearchTypesButton />

View File

@ -88,7 +88,7 @@ const closeModal = () => {
</script>
<template>
<button class="btn btn-sm btn-success mr-3" @click.stop.prevent="openModal">
<button class="btn btn-sm btn-add mr-3" @click.stop.prevent="openModal">
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
</button>
<Modal

View File

@ -127,7 +127,7 @@ const closeModal = () => {
</script>
<template>
<button class="btn btn-sm btn-success mr-3" @click.stop.prevent="openModal">
<button class="btn btn-sm btn-add mr-3" @click.stop.prevent="openModal">
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
</button>
<Modal

View File

@ -1,6 +1,7 @@
<script setup>
import { ref } from "vue";
import { useRouter } from "vue-router";
import { twMerge } from "tailwind-merge";
const router = useRouter();
//
const mockData = ref([
@ -33,42 +34,42 @@ const mockData = ref([
sub_system_tag: "ECP3",
},
{
title: "Elevator system",
title: "Elevator System",
icon: "building",
isError: false,
main_system_tag: null,
sub_system_tag: null,
},
{
title: "High voltage switchboard",
title: "High Voltage Switchboard",
icon: "charging-station",
isError: false,
main_system_tag: null,
sub_system_tag: null,
},
{
title: "Low voltage switchboard",
title: "Low Voltage Switchboard",
icon: "charging-station",
isError: false,
main_system_tag: null,
sub_system_tag: null,
},
{
title: "Water supply system",
title: "Water Supply System",
icon: "tint",
isError: false,
main_system_tag: null,
sub_system_tag: null,
},
{
title: "Sewage and wastewater equipment",
title: "Sewage And Wastewater Equipment",
icon: "water",
isError: false,
main_system_tag: null,
sub_system_tag: null,
},
{
title: "Emergency generator",
title: "Emergency Generator",
icon: "car-battery",
isError: false,
main_system_tag: null,
@ -82,35 +83,35 @@ const mockData = ref([
sub_system_tag: null,
},
{
title: "CCTV system",
title: "CCTV System",
icon: "video",
isError: false,
main_system_tag: null,
sub_system_tag: null,
},
{
title: "Access control system",
title: "Access Control System",
icon: "door-open",
isError: false,
main_system_tag: null,
sub_system_tag: null,
},
{
title: "Shutdown system",
title: "Shutdown System",
icon: "car",
isError: false,
main_system_tag: null,
sub_system_tag: null,
},
{
title: "Emergency rescue system",
title: "Emergency Rescue System",
icon: "exclamation-triangle",
isError: false,
main_system_tag: null,
sub_system_tag: null,
},
{
title: "Air supply and exhaust system",
title: "Air Supply Aand Exhaust System",
icon: "wind",
isError: false,
main_system_tag: null,
@ -124,7 +125,7 @@ const navigateToSubSystem = (mainSystemId, subSystemId) => {
params: {
main_system_id: mainSystemId,
sub_system_id: subSystemId,
floor_id: 'main'
floor_id: "main",
},
});
};
@ -135,10 +136,14 @@ const navigateToSubSystem = (mainSystemId, subSystemId) => {
<div
v-for="(item, index) in mockData"
:key="index"
:class="[
'w-full sm:w-1/2 lg:w-1/4 relative my-2 cursor-pointer',
item.sub_system_tag ? '' : 'grayscale opacity-70 cursor-not-allowed'
]"
:class="
twMerge(
'w-full sm:w-1/2 lg:w-1/4 relative my-2 ',
item.sub_system_tag
? 'saturate-200 cursor-pointer text-base text-info'
: 'grayscale opacity-70 cursor-not-allowed text-sm'
)
"
@click="navigateToSubSystem(item.main_system_tag, item.sub_system_tag)"
>
<img
@ -155,7 +160,9 @@ const navigateToSubSystem = (mainSystemId, subSystemId) => {
></FontAwesomeIcon>
</div>
<div class="icon-text">
<div class="text-slate-300 text-sm">{{ item.title }}</div>
<div class="">
{{ item.title }}
</div>
</div>
</div>
</div>

View File

@ -8,6 +8,8 @@ import {
addGraphTableDataWithoutSubSys,
editGraphTableDataWithoutSubSys,
} from "@/apis/graph";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const props = defineProps({
@ -121,10 +123,10 @@ watch(
</script>
<template>
<button class="btn btn-success mr-3" @click.stop.prevent="openModal">
<button class="btn btn-add mr-3" @click.stop.prevent="openModal">
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
</button>
<Modal id="graph_add_item" title="圖資上傳" :onCancel="onCancel" width="800">
<Modal id="graph_add_item" :title="t('graphManagement.upload')" :onCancel="onCancel" width="800">
<template #modalContent>
<form ref="form" class="mt-5">
<div class="mb-2">

View File

@ -76,15 +76,19 @@ const isSearchButtonDisabled = computed(() => {
const submitBtns = computed(() => [
{
title: t("button.query"),
title: t("button.search"),
key: "submit",
active: false,
onClick: submit,
icon: "search",
btn: "btn-search",
disabled: isSearchButtonDisabled.value,
},
{
title: t("button.export"),
key: "export",
icon: "download",
btn: "btn-export",
active: false,
onClick: (e) => submit(e, "export"),
disabled: isSearchButtonDisabled.value,
@ -120,7 +124,7 @@ watch(
status="info"
:cancel="cancelToastOpen"
/>
<ButtonGroup class="ml-5" :items="submitBtns" :withLine="false" />
<ButtonGroup class="ml-5" :items="submitBtns" :withLine="false" :withBtnClass="true"/>
</template>
<style lang="scss" scoped></style>

View File

@ -29,14 +29,14 @@ const initializeItems = () => {
: true,
Type: 1,
},
{
title: t("history.time_range"),
key: "startMonthTime",
active: searchParams.value.Type
? parseInt(searchParams.value.Type) === 2
: false,
Type: 2,
},
// {
// title: t("history.time_range"),
// key: "startMonthTime",
// active: searchParams.value.Type
// ? parseInt(searchParams.value.Type) === 2
// : false,
// Type: 2,
// },
]);
itemsForStartTime.value = [

View File

@ -10,6 +10,8 @@ const { searchParams, changeParams } = useSearchParam();
const selectedBuilding = ref([]);
const deviceData = ref([]);
const searchTerm = ref(""); //
const activeSearchTerm = ref("");
const getDeviceData = async (sub_tag, renew) => {
const res = await getHistorySideBar(sub_tag);
@ -162,6 +164,28 @@ const changeSelected = (Device_list, renew = false) => {
});
}
};
const filteredDeviceData = computed(() => {
if (!activeSearchTerm.value) return deviceData.value;
return deviceData.value.map((building) => ({
...building,
floors: building.floors.map((floor) => ({
...floor,
devices: floor.devices.filter((device) =>
device.device_name.includes(activeSearchTerm.value)
),
})).filter(floor => floor.devices.length > 0)
})).filter(building => building.floors.length > 0);
});
const handleSearch = (e) => {
e.preventDefault();
activeSearchTerm.value = searchTerm.value;
};
const handleInput = (e) => {
searchTerm.value = e.target.value;
};
</script>
<template>
@ -175,12 +199,15 @@ const changeSelected = (Device_list, renew = false) => {
/>
<input
type="text"
:value="searchTerm"
@input="handleInput"
:placeholder="t('button.enter_text')"
class="text-white bg-transparent w-full"
@keyup.enter="handleSearch"
/>
</label>
<ul class="menu text-lg">
<template v-for="building in deviceData" :key="building.building_tag">
<template v-for="building in filteredDeviceData" :key="building.building_tag">
<li>
<details :open="selectedBuilding.includes(building.building_tag)">
<summary>

View File

@ -29,8 +29,10 @@ const exportFile = async () => {
const submitBtns = computed(() => [
{
title: t("button.query"),
title: t("button.search"),
key: "submit",
icon: "search",
btn: "btn-search",
active: false,
onClick: search,
disabled: isSearchDisabled.value,
@ -38,6 +40,8 @@ const submitBtns = computed(() => [
{
title: t("button.export"),
key: "export",
icon: "download",
btn: "btn-export",
active: false,
onClick: exportFile,
disabled: isSearchDisabled.value,
@ -84,10 +88,11 @@ watch(
<ButtonGroup
:items="submitBtns"
:withLine="false"
:withBtnClass="true"
class="ml-5 mr-8 xl:mr-10"
/>
<button class="btn btn-info" @click.stop.prevent="() => openModal()">
<button class="btn btn-add" @click.stop.prevent="() => openModal()">
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
</button>
</template>

View File

@ -38,7 +38,7 @@ const setButtonItems = () => {
params: ["work_type", "sub_system_tag"],
},
{
title: t('operation.maintainance'),
title: t('operation.maintenance'),
key: "maintain",
active: searchParams.value.work_type === "1",
work_type: 1,

View File

@ -229,7 +229,7 @@ watch(
"work_type"
)
) {
const work_types = [t("operation.maintainance"), t("operation.repair")];
const work_types = [t("operation.maintenance"), t("operation.repair")];
formState.value[searchParams.value?.work_type - 1].work_type =
searchParams.value.work_type;
formState.value[searchParams.value?.work_type - 1].work_type_name =

View File

@ -56,12 +56,11 @@ const getData = async () => {
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) => ({
...d, key: d.full_name, device_list: d.device_list.filter(({ device_coordinate_3d }) => device_coordinate_3d).map((dev, index) => ({
...dev,
forge_dbid: parseInt(dev.forge_dbid),
device_coordinate_3d: dev.device_coordinate_3d
? JSON.parse(dev.device_coordinate_3d)
: null,
room_dbid: parseInt(dev.room_dbid),
device_coordinate_3d: JSON.parse(dev.device_coordinate_3d),
alarmMsg: "",
is_show: true,
currentColor: dev.device_normal_point_color,
@ -195,9 +194,7 @@ const getCurrentInfoModalData = async (e, position, value) => {
}
const mobile = isMobile(e);
selectedDevice.value = {
initPos: mobile
? { left: `50%`, top: `50%` }
: { left: `${position.left}px`, top: `${position.top}px` },
initPos: { left: `50%`, top: `50%` },
value,
isMobile: mobile,
};
@ -207,7 +204,7 @@ const getCurrentInfoModalData = async (e, position, value) => {
const selectedDeviceRealtime = computed(() => realtimeData.value?.find(({ device_number }) => device_number === selectedDevice.value?.value?.device_number)?.data)
const clearSelectedDeviceInfo = () => {
selectedDevice.value.value = null;
}

View File

@ -1,19 +1,18 @@
<script setup>
import { computed, inject, watch } from "vue"
import useSelectedFloor from "@/hooks/useSelectedFloor"
const { data } = inject("system_deviceList")
import useSystemShowData from "@/hooks/useSystemShowData"
const { getCurrentInfoModalData } = inject("system_selectedDevice")
const { selectedFloor } = useSelectedFloor()
const { showData } = useSystemShowData()
const showData = computed(() => selectedFloor.value?.key === 'main' ? data.value : data.value.filter(({ floor_guid }) => floor_guid === selectedFloor.value?.key) || [])
watch(selectedFloor, (newValue) => {
console.log(newValue)
})
const fitToView = (forge_dbid) => {
// console.log(forge_dbid)
// window.NOP_VIEWER.hide(forge_dbid + 3);
// window.NOP_VIEWER.impl.invalidate(true);
window.NOP_VIEWER.fitToView([forge_dbid])
}
</script>
<template>
@ -39,7 +38,7 @@ watch(selectedFloor, (newValue) => {
<span>{{ device.device_status }}</span>
</div>
<button class="btn-text border-0 "
@click.stop.prevent="(e) => getCurrentInfoModalData(e, { left: e.clientX, top: e.clientY }, device)">{{
@click.prevent="(e) => getCurrentInfoModalData(e, { left: e.clientX, top: e.clientY }, device)">{{
$t("system.details") }}</button>
</div>
</div>

View File

@ -39,7 +39,7 @@ const onClick = (item) => {
router.push({
name: 'sub_system', params: {
...route.params, floor_id: item.key
}, query: { ...route.query, gas: route.query.gas }
}, query: { ...route.query, gas: route.query.gas, mode: route.params.floor_id === "main" ? "3D" : route.query.mode }
})
}

View File

@ -33,7 +33,7 @@ watch(
<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' : ''">
:modalStyle="position" class="-translate-x-1/2 -translate-y-1/2">
<template #modalContent>
<SystemInfoModalContent />
</template>