This commit is contained in:
Hcat
2023-12-22 14:55:05 +08:00
parent 68d121091f
commit 65510ce59d
10 changed files with 463 additions and 208 deletions

44
src/api/tunnelScene.js Normal file
View File

@@ -0,0 +1,44 @@
import request from "@/utils/request.js";
// 设备类型
export const getEquipmentType = () => {
return request({
url: "/tunnel/model/equipment/type/option",
method: "get",
});
};
// 获取设备
export const getEquipment = (tunnelId, typeKey, equipmentIds = "1") => {
return request({
url: "/tunnel/model/equipment/option",
method: "post",
params: {
tunnelId,
typeKey,
equipmentIds,
},
});
};
// 初始化数据
export const initSceneData = (tunnelId) => {
return request({
url: `/tunnel/model/${tunnelId}`,
method: "get",
});
};
// 添加设备
export const saveEquipment = (
constructionLength,
tunnelId,
tunnelThreeConfig
) => {
return request({
url: "/tunnel/model",
method: "put",
data: {
constructionLength,
tunnelId,
tunnelThreeConfig,
},
});
};

View File

@@ -4,7 +4,8 @@
<dev-info ref="info" :devInfo="devInfo" />
<!-- 这里的预览模式需要做成不能修改的模式 -->
<edit-dialog ref="edit" @addEquipment="handleAddEqu" @removeEquipment="handleRemoveEqu" @cancel="handleCancel"
:hasDev="hasDevice" :pointNum="pointNum" pointGap="500" />
:hasDev="hasDevice" :pointNum="pointNum" :tunnelId="tunnelId" :position="targetP?.name" :hasEquipment="hasDevice"
pointGap="500" />
<el-dialog v-model="centerDialogVisible" width="30%" destroy-on-close center :show-close="false" style="
margin: 20% auto;
width: 569px;
@@ -48,22 +49,22 @@ import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import { onMounted, reactive, ref } from "vue";
import { ElMessage } from "element-plus";
import { useModelSceneStore } from "@/store/modelSceneStore";
// 获取html标签跟随组件dom
const content = ref(null);
const info = ref(null);
const edit = ref(null);
let demo; //定义demo全局变量
// const loader = new OBJLoader();
const store = useModelSceneStore();
let demo; //定义demo对象
const loader = new OBJLoader();
let hdrLoader = new RGBELoader();
let backColorSet = three.sRGBEncoding;
const params = defineProps(["isedit"]); //接收参数看是不是编辑模式,如果是编辑模式,则需要做一些处理
// alert(params.isedit)
let isedit = ref(params.isedit)
const params = defineProps(["isedit", "tunnelId"]); //接收参数看是不是编辑模式,如果是编辑模式,则需要做一些处理
let isedit = ref(params.isedit);
onMounted(handleMounted);
// 挂载后回调
@@ -72,7 +73,11 @@ async function handleMounted() {
demo = new ThreeDScene(three, content.value);
//看是不是预览模式,然后继续相关的操作(会在demo中的初始化中进行)
demo.isedit = params.isedit;
let tunnelasync = await demo.loadModel(GLTFLoader, "./assets/tunnelModel/chanel.gltf");
const loaded = await demo.loadModel(
GLTFLoader,
"./assets/tunnelModel/chanel.gltf"
);
demo.addOrbitControls(OrbitControls);
demo.addTween(TWEEN);
demo.addCSS3Renderer(CSS3DRenderer, CSS3DSprite, doms);
@@ -82,19 +87,21 @@ async function handleMounted() {
//加载HDR背景图片
demo.loadBackground(hdrLoader, backColorSet);
const text = await store.initData();
// 初始化设备模型
try {
const map = new Map();
map.set("equ_fan", await loadModel("/devicesModel/model2.obj"));
map.set("equ_sensors", await loadModel("/devicesModel/sensors.obj"));
// 给对象初加载设备模型
demo.initDevicesModel(map);
await Promise.all([map.get("equ_fan"), map.get("equ_sensors")]);
// demo.tunnelModeInit()
// 初始化
const equipmentList = await store.getEquipmentList();
demo.editTunnelInit(equipmentList);
} catch (err) {
console.log(err);
ElMessage({
message: "场景加载异常!",
type: "warning",
});
}
}
@@ -148,54 +155,39 @@ function lClickCallback(demo) {
}
editDevInfo(targetPoint.info);
}
// 传给内部使用
demo.addFunction("displayDevInfo", displayDevInfo);
}
let pointNum = ref(0);
let targetP;
let targetP = ref({});
// 右键点击附着点后调函数
function rClickCallback(demo) {
function editDev(targetPoint = null) {
hasDevice = targetPoint.hasDevice;
targetP = targetPoint;
hasDevice.value = targetPoint.hasDevice;
targetP.value = targetPoint;
pointNum.value = Number(
targetPoint.name.substring(
targetPoint.name.indexOf("_") + 1,
targetPoint.name.lastIndexOf("_")
) - 1
);
if (!targetPoint.info) return;
editDevInfo(targetPoint.info);
}
demo.addFunction("editDev", editDev);
}
// 添加设备
// 场景添加设备
function handleAddEqu(formInfo) {
if (!formInfo.equipmentType) {
ElMessage({
message: "请选择传感器!",
type: "warning",
});
return;
}
//表单信息
//这里利用处理请求
demo.addEquipment(targetP, formInfo);
ElMessage({
message: "添加成功!",
type: "success",
});
demo.addEquipment(targetP.value, formInfo);
}
const centerDialogVisible = ref(false);
// 删除设备
function handleRemoveEqu() {
if (!targetP.hasDevice) {
if (!targetP.value.hasDevice) {
ElMessage({
message: "该点位不存在设备!",
type: "warning",
@@ -206,12 +198,23 @@ function handleRemoveEqu() {
}
// 对话框确认删除
function handleConfirmAddEqu() {
demo.removeEquipment(targetP);
centerDialogVisible.value = false;
ElMessage({
message: "删除成功!",
type: "success",
});
console.log("target:", targetP.value.info);
store
.deleteEquipment(10000, params.tunnelId, targetP.value.info.equipmentId)
.then((res) => {
demo.removeEquipment(targetP.value);
centerDialogVisible.value = false;
ElMessage({
message: "删除成功!",
type: "success",
});
})
.catch((err) => {
ElMessage({
message: "请求异常!",
type: "warning",
});
});
}
// 处理取消关闭编辑框事件
function handleCancel() {
@@ -221,8 +224,32 @@ function handleCancel() {
demo._resetState();
demo.clearTagsObj();
}
//现在首先有二种方案是写在TunnelScene.vue中还是demo.js中呢
//我认为可能看数据在哪获取到时候看在哪里导入首先我们放在TunnelScene里面吧
//因为没获取到接口,我们先写死!!!
//需要参考接口的数据结构!!!,主要是传入函数的参数应该是什么结构???
const ThreeConfig = {
code: 0,
data: {
tunnelThreeConfig: [
{
equipmentId: "fan_01", //传感器id
equipmentName: "01", //设备名称
pointName: "point_005_tl", //附着点名称(定位)
equipmentType: "fan", //设备类型(类型可根据后端
equipmentValue: 23, //设备存的值
},
{
equipmentId: "sensors_01", //传感器id
equipmentName: "01", //设备名称
pointName: "point_009_bl", //附着点名称(定位)
equipmentType: "sensors", //设备类型(类型可根据后端
equipmentValue: 67, //设备存的值
},
],
},
msg: "dda",
};
</script>
<style lang="scss" scoped>

View File

@@ -0,0 +1,113 @@
<template>
<div id="select-input">
<div class="select">
<div class="value" @click="isShowList = !isShowList">
<span>{{ selectedVal }}</span>
<img src="/images/htmlEditDialog/select-icon.png" alt="" />
</div>
<ul v-show="isShowList">
<li
v-for="(item, index) of params.options"
:key="index"
@click="handleClickItem(item)"
>
{{ item.label }}
</li>
</ul>
</div>
</div>
</template>
<script setup>
import { ref, defineEmits, defineProps, defineExpose } from "vue";
const params = defineProps({
options: Array,
placeholder: String,
});
const emit = defineEmits(["selectChange"]);
let isShowList = ref(false);
let selectedVal = ref(params.placeholder);
function handleClickItem(item) {
if (!item.value) return;
selectedVal.value = item.label;
isShowList.value = false;
emit("selectChange", item);
}
function reset() {
isShowList.value = false;
selectedVal.value = params.placeholder;
}
defineExpose({
reset,
});
</script>
<style lang="scss" scoped>
#select-input {
P {
width: 130px;
height: 35px;
font-size: 26px;
font-family: MicrosoftYaHei;
color: #ffffff;
line-height: 35px;
}
.select {
position: relative;
.value {
width: 284px;
height: 51px;
border: 1px solid #0f82af;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #08b7b8;
line-height: 51px;
margin-top: 20px;
padding: 0px 0px 0px 10px;
position: relative;
img {
position: absolute;
right: 20px;
bottom: 18px;
cursor: pointer;
}
img:active {
transform: scale(0.9);
}
}
ul {
position: absolute;
width: 284px;
max-height: 300px;
background: #072247;
border-radius: 0px 0px 20px 20px;
border: 1px solid #0f82af;
z-index: 10000;
overflow-y: scroll;
li {
// height: 37px;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #ffffff;
line-height: 37px;
padding: 10px 10px;
cursor: pointer;
}
li:hover {
color: #08b7b8;
background: #0f82af8f;
}
}
ul::-webkit-scrollbar {
height: 20px;
width: 20;
}
ul::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: #53535380;
}
}
}
</style>

View File

@@ -2,25 +2,39 @@
<div id="edit-dialog">
<div class="distance-back">
<p>当前距离洞口{{ pointDistance_str }}</p>
<img src="/images/htmlEditDialog/back-icon.png" alt="" @click="handleCancel" />
<img
src="/images/htmlEditDialog/back-icon.png"
alt=""
@click="handleCancel"
/>
</div>
<div class="equ-info">当前风压:{{ p }}Pa</div>
<div class="setting">
<div class="setting-item">
<p>传感器类型</p>
<el-select v-model="equipmentSetting.equipmentType" :fit-input-width="true" filterable clearable
placeholder="请选择设备类型">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<select-input
:options="options"
@selectChange="handleTypeChange"
placeholder="请选择传感器类型"
ref="equipmentType"
/>
</div>
<div class="setting-item">
<p>设备选择</p>
<el-select v-model="equipmentSetting.chooseEquipment" :fit-input-width="true" filterable clearable
placeholder="请选择设备类型">
<el-option v-for="item in options2" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<select-input
:options="options2"
@selectChange="handleEquipmentChange"
placeholder="请选择设备"
ref="equipment"
/>
</div>
<input-num name="阈值" placeholder="请输入阈值" @inputValue="handelInput" :disabled="isDisabledInputNum" />
<input-num
name="阈值"
placeholder="请输入阈值"
@inputValue="handelInput"
:disabled="isDisabledInputNum"
/>
</div>
<div class="btn">
<button @click="removeEquipment">删除</button>
@@ -31,84 +45,81 @@
<script setup>
import InputNum from "./childComps/InputNum.vue";
import SelectInput from "./childComps/SelectInput.vue";
import { getEquipmentType, getEquipment } from "@/api/tunnelScene";
import { reactive, computed, defineEmits, defineProps, watch, ref } from "vue";
import { useModelSceneStore } from "@/store/modelSceneStore";
import { ElMessage } from "element-plus";
import {
reactive,
computed,
defineEmits,
defineProps,
watch,
nextTick,
ref,
} from "vue";
// 定义事件发射器,父组件监听
const emit = defineEmits(["cancel", "removeEquipment", "addEquipment"]);
const params = defineProps(["pointNum", "pointGap"]); //隧道第几个锚点
const params = defineProps([
"pointNum",
"pointGap",
"tunnelId",
"position",
"hasEquipment",
]);
// 当前风压
let p = ref(57);
const equipment = ref(null);
const equipmentType = ref(null);
const store = useModelSceneStore();
//计算锚点之间距离
const pointDistance_str = computed(
() =>
`${params.pointGap}米*${params.pointNum}=${params.pointGap * params.pointNum
`${params.pointGap}米*${params.pointNum}=${
params.pointGap * params.pointNum
}`
);
// 请求数据模型
const equipmentSetting = reactive({
equipmentType: "", //设备类型
chooseEquipment: "", //设备选择(设备名称)
chooseEquipment: null, //设备选择(设备名称)
threshold: "", //阈值
});
// 绑定选择的设备类型
function handleTypeChange(optionItem) {
equipmentSetting.equipmentType = optionItem.value;
}
function handleEquipmentChange(equipmentItem) {
equipmentSetting.chooseEquipment = equipmentItem;
}
// 设备类型选项参数
const options = reactive([
{ label: "风机", value: "fan" },
{ label: "风压传感器", value: "sensors" },
{ label: "普通传感器", value: "sensors_2" },
]);
let options = reactive([{ label: "暂无数据", value: "" }]);
// 设备编号参数
let options2 = reactive([]);
let options2 = reactive([{ equipmentId: 0, label: "暂无数据", value: "" }]);
let isDisabledInputNum = ref(false);
// 模拟生成option2
watch(
() => equipmentSetting.equipmentType,
() => {
let label;
options2 = [];
equipmentSetting.chooseEquipment = "";
isDisabledInputNum = false;
if (equipmentSetting.equipmentType === "fan") {
label = "风机";
isDisabledInputNum = true;
}
if (equipmentSetting.equipmentType === "windPressure") label = "风压传感器";
if (equipmentSetting.equipmentType === "sensors") label = "普通传感器";
for (let i = 1; i < 11; i++) {
options2.push({ label: `${i}${label}`, value: `${label}_${i}` });
}
(newVal) => {
console.log(params.tunnelId, newVal);
equipment.value.reset();
getEquipment(params.tunnelId, newVal, 1).then((res) => {
options2.splice(0, options2.length);
options2.push(
...res.data.map((item) => {
return {
equipmentId: item.equipmentId,
label: item.equipmentName,
value: item.equipmentType,
};
})
);
});
}
);
// const obj = {
// equipmentId: String, //传感器id
// equipmentName: String, //设备名称
// pointName: String, //附着点名称(定位)
// equipmentType: String, //设备类型(类型可根据后端)
// equipmentOnline: Boolean, //是否在线
// isFan: Boolean, //是不是风机
// fanSpeed: Number, //F
// };
// const tunnel = {
// tunnelId: "",
// };
// 显示锚点距离
let point_num = ref(0);
// 设备类型请求
getEquipmentType()
.then((res) => {
options.splice(0, options.length);
options.push(...res.data);
})
.catch((err) => console.log(err));
function handelInput(e) {
equipmentSetting.threshold = e;
@@ -116,6 +127,11 @@ function handelInput(e) {
// 处理取消事件
function handleCancel() {
equipmentSetting.equipmentType = "";
equipmentSetting.chooseEquipment = null;
equipmentSetting.threshold = "";
equipment.value.reset();
equipmentType.value.reset();
// 发射事件给tunnel父组件
emit("cancel");
}
@@ -127,20 +143,44 @@ function removeEquipment() {
// 添加设备
function addEquipment() {
emit("addEquipment", equipmentSetting);
equipmentSetting.chooseEquipment = "";
equipmentSetting.equipmentType = "";
equipmentSetting.threshold = "";
if (params.hasEquipment) {
ElMessage({
message: "该点位已存在设备!",
type: "warning",
});
return;
}
if (!equipmentSetting.equipmentType || !equipmentSetting.chooseEquipment) {
ElMessage({
message: "选项不能为空!",
type: "warning",
});
return;
}
equipmentSetting.position = params.position;
// 合法请求
store
.saveSceneData(10000, 1, equipmentSetting)
.then((res) => {
emit("addEquipment", equipmentSetting);
equipmentSetting.chooseEquipment = null;
equipmentSetting.equipmentType = "";
equipmentSetting.threshold = "";
equipment.value.reset();
equipmentType.value.reset();
ElMessage({
message: "添加成功!",
type: "success",
});
})
.catch((err) => {
ElMessage({
message: "请求异常!",
type: "warning",
});
});
}
const equipmentType = {
label: String, //传感器类型
typeId: String, //传感器类型ID(方便查找该类型的所有设备)
};
// 通过以上选项请求以下具体哪个设备
const equipment = {
label: String, //传感器编号加名称
equId: String, // 传感器Id
};
</script>
<style lang="scss" scoped>
@@ -203,40 +243,6 @@ const equipment = {
margin-bottom: 20px;
}
}
:deep(.el-select) {
width: 284px;
//height: 51px;
border: transparent;
}
:deep(.el-input--suffix) {
width: 284px;
height: 51px;
background: rgba(7, 35, 72, 0.79);
border: 2px solid #0f82af;
}
:deep(.el-input__wrapper) {
background: transparent;
border: none !important;
padding: 0px 12px 0px 10px;
box-shadow: none !important;
}
:deep(.el-input__wrapper input) {
background: transparent;
height: 100%;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #08b7b8;
line-height: 37px;
}
:deep(.el-icon) {
color: #05feff;
font-size: 34px;
}
}
.btn {
@@ -244,16 +250,9 @@ const equipment = {
display: flex;
justify-content: space-between;
button[disabled] {
color: grey !important;
opacity: 1
}
button {
cursor: pointer;
transition: transform 0.1s linear 0s;
}
& :nth-child(1) {

View File

@@ -8,9 +8,9 @@ import {
} from "./handleOrbitControlsChange";
import { saveState, resetState } from "./viewBack";
import addFunction from "./addEvent";
import { editTunnelInit } from "./editTunnelInit";
import { addEquipment, removeEquipment } from "./editEquipment";
import previewtunnelModeInit from "./previewTunnelInit"
import { Group } from "three/examples/jsm/libs/tween.module";
export default class Demo {
// 摄像机看向位置
origin = null;
@@ -28,6 +28,7 @@ export default class Demo {
this.addEquipment = addEquipment;
this.removeEquipment = removeEquipment;
this.previewtunnelModeInit = previewtunnelModeInit;
this.editTunnelInit = editTunnelInit;
// 外部可添加函数
this.addFunction = addFunction;
@@ -173,6 +174,7 @@ export default class Demo {
// 改变为基础材质
child.material = new this.THREE.MeshBasicMaterial();
child.scale.set(0.01, 0.01, 0.01);
if (/b[rl]$/.test(child.name)) child.translateZ(2);
// 遍历一个属性是否存在设备
child.hasDevice = false; //初始化
}
@@ -380,10 +382,10 @@ export default class Demo {
// console.log(v);
}
});
const axesHelper = new this.THREE.AxesHelper(100);
// const axesHelper = new this.THREE.AxesHelper(100);
// 改变叶子旋转中心
let x = 0,
y = -0.2,
y = -0.2099,
z = 0;
const wrapper = new this.THREE.Object3D();
wrapper.position.set(x, y, z);
@@ -395,24 +397,23 @@ export default class Demo {
this.equMap.get("equ_fan").add(wrapper);
// 初其他传感器机颜色
this.equMap.get("equ_sensors").scale.set(0.1, 0.1, 0.1);
this.equMap.get("equ_sensors").scale.set(0.2, 0.2, 0.2);
this.equMap.get("equ_sensors").traverse((v) => {
v.material = new this.THREE.MeshBasicMaterial();
v.material.color = new this.THREE.Color("#7e7b7b");
v.material.color = new this.THREE.Color("white");
});
// 初始标签面板
const tag = new this.THREE.Mesh(
new this.THREE.PlaneGeometry(10, 4),
new this.THREE.PlaneGeometry(7, 5),
new this.THREE.MeshBasicMaterial({ color: "white" })
);
this.equMap.get("equ_sensors").rotation.x += Math.PI / 2;
this.equMap.get("equ_sensors").add(tag);
// const axesHelper = new this.THREE.AxesHelper(100);
// this.equMap.get("equ_sensors").add(axesHelper);
tag.name = "tag";
tag.rotation.x = Math.PI / 2;
tag.rotation.z = Math.PI / 2; //旋转这里改变文字顺序
tag.rotation.y = Math.PI;
tag.rotation.z -= Math.PI / 2;
tag.translateZ(2.0);
}
@@ -430,11 +431,6 @@ export default class Demo {
this.distance = distance;
}
loadBackground(hdrLoader, backColorSet) {
// hdrLoader.load("/images/background/background.hdr", (texture) => {
// texture.mapping = this.THREE.EquirectangularReflectionMapping;
// this.scene.background = texture;
// this.scene.environment = texture;
// })
this.scene.background = new this.THREE.TextureLoader().load(
"/images/background/background.png",
function (texture) {

View File

@@ -5,20 +5,20 @@ import EquipmentTag from "../utils/EquipmentTag";
* @param {String} equType "fan" "sensors"
*/
//formInfo需要的信息这里包括了
//equipmentType
//equipmentType
function addEquipment(targetPoint, formInfo) {
if (targetPoint.hasDevice) {
alert("已添加设备");
return;
}
switch (formInfo.equipmentType) {
case "fan":
handleFanEqu.call(this, targetPoint);
case "frequency":
handleFanEqu.call(this, targetPoint, formInfo.chooseEquipment);
break;
case "sensors":
case "sensors_2":
handleOtherEqu.call(this, targetPoint, formInfo.equipmentType);
case "windPressure":
case "sensor":
handleOtherEqu.call(this, targetPoint, formInfo.chooseEquipment);
break;
default:
break;
@@ -28,47 +28,50 @@ function addEquipment(targetPoint, formInfo) {
this.clearTagsObj();
}
// 其他传感器
function handleOtherEqu(targetPoint, EqeName) {
function handleOtherEqu(targetPoint, equipmentInfo) {
const equMesh = this.equMap.get("equ_sensors").clone();
const worldP = targetPoint.getWorldPosition(new this.THREE.Vector3());
equMesh.position.copy(worldP);
//设备添加标签
const tag = EquipmentTag(EqeName === "sensors" ? "风压传感器" : "普通传感器");
const tag = EquipmentTag(equipmentInfo.label);
console.log(equipmentInfo);
equMesh.getObjectByName("tag").material = tag;
if (/tr$/.test(targetPoint.name)) {
equMesh.rotation.z = -(3 * Math.PI) / 4;
targetPoint.scale.set(0.03, 0.03, 0.03);
equMesh.getObjectByName("tag").rotation.z += Math.PI; ///注意在原来的基础上加
equMesh.rotation.z = -Math.PI / 2;
equMesh.rotation.y -= Math.PI / 4;
equMesh.getObjectByName("tag").rotation.z += Math.PI; // 注意在原来的基础上加
} else if (/tl$/.test(targetPoint.name)) {
equMesh.rotation.z = -(5 * Math.PI) / 4;
targetPoint.scale.set(0.03, 0.03, 0.03);
equMesh.rotation.z = Math.PI / 2;
equMesh.rotation.y += Math.PI / 4;
equMesh.getObjectByName("tag").rotation.z += Math.PI;
} else if (/tc$/.test(targetPoint.name)) {
equMesh.rotation.z = Math.PI;
targetPoint.scale.set(0.03, 0.03, 0.03);
equMesh.getObjectByName("tag").rotation.z += Math.PI;
} else if (/br$/.test(targetPoint.name)) {
equMesh.rotation.z = -Math.PI / 2;
equMesh.translateX(-1);
equMesh.getObjectByName("tag").rotation.z += Math.PI; ///注意在原来的基础上加
targetPoint.scale.set(0.03, 0.03, 0.075);
equMesh.getObjectByName("tag").rotation.z += Math.PI;
} else if (/bl$/.test(targetPoint.name)) {
equMesh.rotation.z = Math.PI / 2;
equMesh.translateX(1);
targetPoint.scale.set(0.03, 0.03, 0.075);
equMesh.getObjectByName("tag").rotation.z += Math.PI;
}
targetPoint.scale.set(0.03, 0.06, 0.05);
this.scene.add(equMesh);
targetPoint.visible = false;
// 保存该设备id后期直接从附附着点进行删除
// 保存该设备模型id后期直接从附附着点进行删除
targetPoint.info = {
id: equMesh.id,
...equipmentInfo,
};
}
// 风机
function handleFanEqu(targetPoint, speed = Math.random().toFixed(1) * 1000) {
function handleFanEqu(
targetPoint,
equipmentInfo,
speed = Math.random().toFixed(1) * 1000
) {
// 由于风机比较多,每个风机转速不一直,保存在一个数中遍历
if (!this.fanSpinArray) {
this.fanSpinArray = [];
@@ -84,6 +87,7 @@ function handleFanEqu(targetPoint, speed = Math.random().toFixed(1) * 1000) {
// 保存该设备id后期直接从附附着点进行删除
targetPoint.info = {
id: equMesh.id, //模型在场景id
...equipmentInfo,
};
// 定义风机旋转
@@ -107,5 +111,6 @@ function removeEquipment(targetPoint) {
targetPoint.visible = true;
targetPoint.hasDevice = false;
targetPoint.scale.set(0.01, 0.01, 0.01);
delete targetPoint.info; // 清空设备信息
}
export { addEquipment, removeEquipment };

View File

@@ -0,0 +1,10 @@
export function editTunnelInit(equipmentList) {
equipmentList.forEach((item) => {
const formInfo = {
equipmentType: item.equipmentType, //设备类型
chooseEquipment: item.chooseEquipment, //设备选择(设备名称)
threshold: item.threshold,
};
this.addEquipment(this.scene.getObjectByName(item.position), formInfo);
});
}

View File

@@ -1,18 +1,25 @@
import * as THREE from "three";
/**
* 返回一个带有文字的几何平面
* @param {String} text 把输入的文字转化为base64的img图片
* 返回一个带有文字的的#3D材质
* 把输入的文字转化为base64的img图片
* @param {String} text
* @param {String} param 传感器实时检测参数
*/
export default function (text, width = 100, height = 50) {
export default function (text = "", param = "50", width = 80, height = 50) {
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
ctx.fillStyle = "white";
ctx.fillStyle = "#00b8ec";
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = "black";
ctx.font = "16px serif";
ctx.fillText(text, (100 - text.length * 16.6) / 2, 30);
ctx.fillStyle = "white";
ctx.font = "12px serif";
ctx.fillText(text, (100 - text.length * 15) / 2, 20);
ctx.fillText(param, (100 - param.length * 10) / 2, 40);
ctx.strokeStyle = "white";
ctx.moveTo(0, 26);
ctx.lineTo(100, 26);
ctx.stroke();
const base64 = canvas.toDataURL();
return new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load(base64),

View File

@@ -0,0 +1,54 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { saveEquipment, initSceneData } from "../api/tunnelScene";
import { ElMessage } from "element-plus";
export const useModelSceneStore = defineStore("modelSceneData", () => {
let equipmentList = ref("[]");
function initData(tunnelId = 1) {
initSceneData(tunnelId)
.then((res) => {
equipmentList.value = res.data.tunnelThreeConfig;
})
.catch((Error) => {
ElMessage.error("场景初始化异常!");
});
}
//默认初始化1号隧道
function saveSceneData(constructionLength, tunnelId, modelData) {
const temp = JSON.parse(equipmentList.value);
temp.push(modelData);
equipmentList.value = JSON.stringify(temp);
console.log("save:", equipmentList.value);
return saveEquipment(constructionLength, tunnelId, equipmentList.value);
}
// 删除设备
function deleteEquipment(constructionLength, tunnelId, EquipmentId) {
let temp = JSON.parse(equipmentList.value);
temp = temp.filter(
(item) => item.chooseEquipment.equipmentId != EquipmentId
);
equipmentList.value = JSON.stringify(temp);
return saveEquipment(constructionLength, tunnelId, equipmentList.value);
}
function getEquipmentList(tunnelId = 1) {
return new Promise((resolve, reject) => {
initSceneData(tunnelId)
.then((res) => {
equipmentList.value = res.data.tunnelThreeConfig;
resolve(JSON.parse(equipmentList.value));
})
.catch((Error) => {
ElMessage.error("场景初始化异常!");
reject();
});
});
}
return {
equipmentList,
initData,
saveSceneData,
deleteEquipment,
getEquipmentList,
};
});

View File

@@ -25,7 +25,7 @@
</div>
</div>
<!-- 这里就导入正常的编辑模式就是我们之前写的部分 -->
<tunnel-scene id="tunnel-box" :isedit="true" />
<tunnel-scene id="tunnel-box" :isedit="true" :tunnelId="tunnelId" />
</div>
</template>
<script setup>