針對特定模型上色
This commit is contained in:
parent
5e0d6a6236
commit
41fac6cfbb
29
server.js
29
server.js
@ -1,36 +1,35 @@
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const { PORT } = require('./config.js');
|
||||
const express = require("express");
|
||||
const path = require("path");
|
||||
const { PORT } = require("./config.js");
|
||||
|
||||
const app = express();
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
// 🔧 URL rewrite 必須在所有路由之前執行(對應 Vite dev proxy 的行為)
|
||||
app.use((req, res, next) => {
|
||||
if (req.path.startsWith('/forge/api')) {
|
||||
req.url = req.url.replace(/^\/forge\/api/, '/api');
|
||||
req.path = req.path.replace(/^\/forge\/api/, '/api');
|
||||
if (req.path.startsWith("/forge/api")) {
|
||||
req.url = req.url.replace(/^\/forge\/api/, "/api");
|
||||
req.path = req.path.replace(/^\/forge\/api/, "/api");
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
const distPath = path.join(__dirname, 'wwwroot/ibms_ems/dist');
|
||||
const distPath = path.join(__dirname, "wwwroot/ibms_ems/dist");
|
||||
app.use(express.static(distPath));
|
||||
}
|
||||
|
||||
// 👉 API routes(在 rewrite 之後)
|
||||
app.use(require('./routes/auth.js'));
|
||||
app.use(require("./routes/auth.js"));
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
// Vue Router history mode (Express 5 catch-all syntax)
|
||||
app.get('/{*path}', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, 'wwwroot/ibms_ems/dist', 'index.html'));
|
||||
app.get("/{*path}", (req, res) => {
|
||||
res.sendFile(path.join(__dirname, "wwwroot/ibms_ems/dist", "index.html"));
|
||||
});
|
||||
|
||||
} else {
|
||||
// 👉 Dev:只跑 API,不管前端
|
||||
app.get('/', (req, res) => {
|
||||
res.send('API server running...');
|
||||
app.get("/", (req, res) => {
|
||||
res.send("API server running...");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import background from "@/assets/bg_tech.jpg";
|
||||
import titleLogo from "@/assets/title.png";
|
||||
import ForgeViewer from "@/components/ForgeViewer.vue";
|
||||
import Info from "@/components/Info.vue";
|
||||
import { ref, useTemplateRef, watch } from "vue";
|
||||
import { ref, useTemplateRef, watch, toRaw } from "vue";
|
||||
import btn01B from "@/assets/btn_01_b.png";
|
||||
import btn01R from "@/assets/btn_01_r.png";
|
||||
import btn02B from "@/assets/btn_02_b.png";
|
||||
@ -83,7 +83,15 @@ const left_data = ref([
|
||||
tag: "ROOM_Information_Data_Center",
|
||||
arcSide: 1,
|
||||
cameraDistance: 5,
|
||||
value: 1.22
|
||||
value: 1.22,
|
||||
content: [
|
||||
"Total Facility Energy: 122,000 kWh",
|
||||
"IT Equipment Energy: 100,000 kWh",
|
||||
"Cooling Energy: 30,000 kWh",
|
||||
"Power System Loss: 6,500 kWh",
|
||||
"Lighting & Others: 3,500 kWh"
|
||||
],
|
||||
spaceColor: new THREE.Vector4(1, 0, 0, 1)
|
||||
},
|
||||
]);
|
||||
|
||||
@ -97,7 +105,16 @@ const right_data = ref([
|
||||
tag: "ROOM_OFFICE",
|
||||
arcSide: 1,
|
||||
cameraDistance: 2,
|
||||
value: 92
|
||||
value: 92,
|
||||
content: [
|
||||
"IAQ Score: 92 / 100",
|
||||
"CO₂ Level: 680 ppm",
|
||||
"PM2.5: 8 μg/m³",
|
||||
"Temperature: 24.5 °C",
|
||||
"Humidity: 52%",
|
||||
"TVOC: 0.28 mg/m³"
|
||||
],
|
||||
spaceColor: new THREE.Vector4(1, 0, 0, 1)
|
||||
},
|
||||
{
|
||||
title: "REAL-TIME THROUGHPUT",
|
||||
@ -108,7 +125,16 @@ const right_data = ref([
|
||||
tag: "TAG_Chiller-Water_Cooled",
|
||||
arcSide: -1,
|
||||
cameraDistance: 10,
|
||||
value: 96
|
||||
value: 96,
|
||||
content: [
|
||||
"Real-Time Throughput: 56%",
|
||||
"Operating Chillers: 4 / 8 units",
|
||||
"Active Cooling Capacity: 5,600 RT",
|
||||
"Available Cooling Capacity: 10,000 RT",
|
||||
"Standby Chillers: 3 units",
|
||||
"Maintenance Chillers: 1 unit"
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "REAL-TIME",
|
||||
@ -119,7 +145,15 @@ const right_data = ref([
|
||||
tag: "TAG_solder_paste_screen_printer",
|
||||
arcSide: -1,
|
||||
cameraDistance: 5,
|
||||
value: 98
|
||||
value: 98,
|
||||
content: [
|
||||
"Predicted Yield (AI): 98.0%",
|
||||
"Target Yield: 98.5%",
|
||||
"Defect Risk: 1.2%",
|
||||
"Quality Deviation: 0.5%",
|
||||
"Key Impact Factor: Temperature Stability",
|
||||
"AI Confidence: 94%"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "SAFETY & ALARMS",
|
||||
@ -140,6 +174,7 @@ const forgeLabelRef = useTemplateRef("forgeLabelRef");
|
||||
|
||||
const imgSrcActive = ref(null);
|
||||
const onClick = (item) => {
|
||||
const viewer = toRaw(forgeViewerRef.value.forgeViewer);
|
||||
|
||||
if (item.tag === "") return
|
||||
imgSrcActive.value = item;
|
||||
@ -147,11 +182,23 @@ const onClick = (item) => {
|
||||
//TODO: 切換視角
|
||||
console.log(forgeLabelRef.value);
|
||||
changeCameraPosition(
|
||||
forgeViewerRef.value.forgeViewer,
|
||||
viewer,
|
||||
forgeLabelRef.value.tagDom,
|
||||
item,
|
||||
);
|
||||
|
||||
item.spaceColor &&
|
||||
viewer.model.getInstanceTree().enumNodeChildren(
|
||||
item.forgeID,
|
||||
(dbId) => {
|
||||
console.log("Found dbId:", dbId);
|
||||
viewer.setThemingColor(dbId, new THREE.Vector4(1, 0, 0, 1)) // RGBA (紅色));
|
||||
viewer.impl.invalidate(true);
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
|
||||
// console.log(forgeViewerRef.value.Viewpoints[7]);
|
||||
// changeCameraView(forgeViewerRef.value.forgeViewer, forgeViewerRef.value.Viewpoints[7].data);
|
||||
};
|
||||
@ -184,6 +231,6 @@ watch(
|
||||
<ForgeViewer ref="forgeViewerRef" :forge-ids="forgeIDs" />
|
||||
<Info position="right" :data="right_data" :imgSrcActive="imgSrcActive?.forgeID" :onClick="onClick" />
|
||||
|
||||
<ForgeLabel ref="forgeLabelRef" v-if="imgSrcActive" :data="imgSrcActive" />
|
||||
<ForgeLabel ref="forgeLabelRef" v-show="imgSrcActive" :data="imgSrcActive" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div id="tag" ref="tag" class="hud-container z-50 hidden">
|
||||
<div class="hud-panel p-5 text-white text-3xl flex justify-center items-center">
|
||||
<div id="tag" ref="tag" class="hud-container hidden z-50 transform -translate-y-1/2">
|
||||
<div class="hud-panel p-5 text-white text-3xl flex flex-col justify-center items-center">
|
||||
<span class="tag_name mr-5">
|
||||
{{ data.title }}
|
||||
{{ data?.title || "" }}
|
||||
</span>
|
||||
<div class="flex flex-col items-start">
|
||||
<span v-for="(value, index) in data.content" :key="index" class="text-xl">
|
||||
{{ value }}
|
||||
<span v-for="(value, index) in data?.content" :key="index" class="text-xl">
|
||||
{{ value || "" }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -143,7 +143,7 @@ watch(forgeViewerDOM, async (newVal) => {
|
||||
|
||||
|
||||
// 根據你的 UI(橢圓框大小)調整
|
||||
const scaleFactor = 1.3; // ⭐ 微調用
|
||||
const scaleFactor = 1; // ⭐ 微調用
|
||||
const direction = cameraPos.clone().sub(cameraTarget).normalize();
|
||||
const distance = cameraPos.distanceTo(cameraTarget) * scaleFactor;
|
||||
const newPos = cameraTarget.clone().add(direction.multiplyScalar(distance));
|
||||
|
||||
@ -200,7 +200,11 @@ export default function changeCameraPosition(forgeViewer, label, item) {
|
||||
console.log("物件中心:", center);
|
||||
|
||||
// ⭐ 計算最佳觀察點
|
||||
const { position, target } = computeCameraOffset(viewer, bbox, item.cameraDistance);
|
||||
const { position, target } = computeCameraOffset(
|
||||
viewer,
|
||||
bbox,
|
||||
item.cameraDistance,
|
||||
);
|
||||
|
||||
// ⭐ 第 1 段:飛到物件
|
||||
const toTarget = {
|
||||
@ -229,9 +233,17 @@ export default function changeCameraPosition(forgeViewer, label, item) {
|
||||
returnToOriginal: true,
|
||||
duration: 5000,
|
||||
item,
|
||||
arcSide: -(item.arcSide),
|
||||
arcSide: -item.arcSide,
|
||||
};
|
||||
flyArc(toOriginal);
|
||||
viewer.model.getInstanceTree().enumNodeChildren(
|
||||
item.forgeID,
|
||||
(dbId) => {
|
||||
viewer.setThemingColor(dbId, null); // RGBA (紅色));
|
||||
viewer.impl.invalidate(true);
|
||||
},
|
||||
true,
|
||||
);
|
||||
viewer.showAll(); // 恢復顯示所有物件
|
||||
}, 8000);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user