Compare commits

..

2 Commits

@ -4,7 +4,7 @@
<!-- <VueThreeMachine /> --> <!-- <VueThreeMachine /> -->
<!-- <vueThreeEquipment /> --> <!-- <vueThreeEquipment /> -->
<!-- <VueGradeGauge /> --> <!-- <VueGradeGauge /> -->
<!-- <StompDemo />--> <!-- <StompDemo /> -->
<el-config-provider :locale="zhCn"> <el-config-provider :locale="zhCn">
<router-view /> <router-view />
</el-config-provider> </el-config-provider>
@ -19,7 +19,7 @@ import viewIndex from '@/layout/view_index.vue';
import zhCn from 'element-plus/es/locale/lang/zh-cn'; import zhCn from 'element-plus/es/locale/lang/zh-cn';
// xq // xq
// F:\vue\workspace\maotu-webtopo\src\components\StompDemo.vue // F:\vue\workspace\maotu-webtopo\src\components\StompDemo.vue
import StompDemo from '@/components/StompDemo.vue'; // import StompDemo from '@/components/StompDemo.vue';
import VueMyTest from '@/components/my-test.vue'; import VueMyTest from '@/components/my-test.vue';
import VueMyButton from '@/components/my-button.vue'; import VueMyButton from '@/components/my-button.vue';
@ -197,6 +197,11 @@ leftAsideStore.registerConfig('vue四遥组件', [
val: '', val: '',
title: '绑定ID' title: '绑定ID'
}, },
showInfo: {
type: 'switch',
val: true,
title: '显示详情'
},
location: { location: {
type: 'select', type: 'select',
val: 'bottom', val: 'bottom',
@ -476,6 +481,12 @@ leftAsideStore.registerConfig('vue公共组件', [
type: 'switch', type: 'switch',
val: true, val: true,
title: '辅助框' title: '辅助框'
},
testStr: {
type: 'map',
val: {},
title: '测试',
disabled: true
} }
} }
}, },

Binary file not shown.

@ -10,7 +10,8 @@ export type ILeftAsideConfigItemPublicPropsType =
| 'upload' | 'upload'
| 'inputSelectId' | 'inputSelectId'
| 'inputTypeTag' //inputTypeTag 必须和 inputSelectId 一起使用 | 'inputTypeTag' //inputTypeTag 必须和 inputSelectId 一起使用
| 'inputSelectImgId'; | 'inputSelectImgId'
| 'map'; //使用这个类型 disabled必须为true(必须隐藏)
// 开放注册配置 // 开放注册配置
export type ILeftAsideConfigItemPublicProps = Record< export type ILeftAsideConfigItemPublicProps = Record<
string, string,

@ -13,7 +13,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'; import { ref, onMounted, onUnmounted } from 'vue';
//threejs // threejs
import { import {
AxesHelper, AxesHelper,
Color, Color,
@ -87,44 +87,51 @@ loader.setDRACOLoader(dracoLoader);
let meshArr: Group[] = []; let meshArr: Group[] = [];
// public\models\nitrogenInjection\nitrogenInjection.gltf // public\models\nitrogenInjection\nitrogenInjection.gltf
loader.load('/models/substation/substation.gltf', (gltf: any) => { loader.load('/models/substation/substation.gltf', (gltf: any) => {
//
loadedModel = gltf.scene;
scene.add(gltf.scene); scene.add(gltf.scene);
const loadTime = Date.now() - startTime; const loadTime = Date.now() - startTime;
// //
controls.update(); // controls.update();
render.render(scene, camera); render.render(scene, camera);
console.log(`大场景模型已加载并显示,总耗时:${loadTime}ms`); console.log(`大场景模型已加载并显示,总耗时:${loadTime}ms`);
loading.value = false; loading.value = false;
}); });
// // //
const ambientLight = new AmbientLight('#ffffff', 1.2); // 0.6 1.0 // const ambientLight = new AmbientLight('#ffffff', 1.2); // 0.6 1.0
scene.add(ambientLight); // scene.add(ambientLight);
// // //
const directionalLight = new DirectionalLight('#ffffff', 1.4); // 0.2 0.8 // const directionalLight = new DirectionalLight('#ffffff', 1.4); // 0.2 0.8
scene.add(directionalLight); // scene.add(directionalLight);
directionalLight.position.set(20, 20, 10); // directionalLight.position.set(20, 20, 10);
// // // // //
const pointLight = new PointLight('#ffffff', 1.4, 1800); // 0.5 1.0 // const pointLight = new PointLight('#ffffff', 1.4, 1800); // 0.5 1.0
scene.add(pointLight); // scene.add(pointLight);
pointLight.position.set(0, 40, 0); // pointLight.position.set(0, 40, 0);
// // // 便
// const rgbELoader = new RGBELoader().load( const rgbELoader = new RGBELoader().load(
// '/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr', '/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
// (envMap: any) => { (envMap: any) => {
// envMap.mapping = EquirectangularReflectionMapping; envMap.mapping = EquirectangularReflectionMapping;
// scene.environment = envMap; scene.environment = envMap;
// } envMapTexture = envMap; //
// ); }
);
// //
const timeline1 = gsap.timeline(); const timeline1 = gsap.timeline();
const timeline2 = gsap.timeline(); const timeline2 = gsap.timeline();
// 便
let loadedModel: any = null;
let envMapTexture: any = null;
// //
function tranlate(position: Vector3, target: Vector3) { function tranlate(position: Vector3, target: Vector3) {
timeline1.to(camera.position, { timeline1.to(camera.position, {
@ -191,11 +198,98 @@ onMounted(() => {
}); });
onUnmounted(() => { onUnmounted(() => {
// console.log('开始清理 Three.js 资源...');
// 1.
// requestAnimationFrame
// 2. ResizeObserver
if ((window as any)._resizeObserver) { if ((window as any)._resizeObserver) {
(window as any)._resizeObserver.disconnect(); (window as any)._resizeObserver.disconnect();
delete (window as any)._resizeObserver; delete (window as any)._resizeObserver;
} }
// 3. GSAP
timeline1.pause();
timeline1.clear();
timeline2.pause();
timeline2.clear();
gsap.globalTimeline.clear();
// 4. DOM
if (div3D.value && render.domElement.parentNode === div3D.value) {
div3D.value.removeChild(render.domElement);
}
// 5.
controls.dispose();
// 6.
if (loadedModel) {
loadedModel.traverse((child: any) => {
if (child.isMesh) {
//
if (child.geometry) {
child.geometry.dispose();
}
//
if (child.material) {
const materials = Array.isArray(child.material) ? child.material : [child.material];
materials.forEach((material: any) => {
//
[
'map',
'normalMap',
'roughnessMap',
'metalnessMap',
'emissiveMap',
'aoMap',
'displacementMap'
].forEach((key) => {
if (material[key]) {
material[key].dispose();
}
});
//
material.dispose();
});
}
}
});
//
scene.remove(loadedModel);
}
// 7.
if (envMapTexture) {
envMapTexture.dispose();
}
// 8.
scene.traverse((child: any) => {
if (child.isLight) {
child.dispose();
}
});
// 9.
while (scene.children.length > 0) {
scene.remove(scene.children[0]);
}
// 10.
render.dispose();
render.forceContextLoss();
render.domElement.remove();
// 11.
scene.clear();
console.log('Three.js 资源清理完成');
}); });
</script> </script>
@ -215,6 +309,7 @@ onUnmounted(() => {
top: 50%; top: 50%;
left: 2%; left: 2%;
transform: translateY(-50%); /* 垂直居中 */ transform: translateY(-50%); /* 垂直居中 */
transform: translateZ(0);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 20px; gap: 20px;

@ -77,15 +77,18 @@ scene.add(camera);
// //
const render = new WebGLRenderer({ const render = new WebGLRenderer({
antialias: false, // 齿 antialias: true, // 齿
powerPreference: 'high-performance', // 使GPU powerPreference: 'high-performance',
stencil: false, // stencil: false,
depth: true, depth: true,
logarithmicDepthBuffer: true // logarithmicDepthBuffer: true,
precision: 'mediump' // 使
}); });
render.setClearColor(new Color('#131519')); render.setClearColor(new Color('#131519'));
render.setPixelRatio(Math.min(window.devicePixelRatio, 2)); //
// //
render.shadowMap.enabled = false; // render.shadowMap.enabled = false;
render.shadowMap.autoUpdate = false; //
// //
const controls = new OrbitControls(camera, render.domElement); const controls = new OrbitControls(camera, render.domElement);
@ -94,15 +97,14 @@ const controls = new OrbitControls(camera, render.domElement);
// controls.autoRotate = false; // controls.autoRotate = false;
// controls.enablePan = false; // // controls.enablePan = false; //
controls.autoRotateSpeed = 1; controls.autoRotateSpeed = 1;
controls.dampingFactor = 0.2; controls.dampingFactor = 0.05; //
controls.rotateSpeed = 0.3; // 1.0 controls.rotateSpeed = 0.5; //
controls.enableDamping = true; controls.enableDamping = false; //
controls.enableRotate = true; controls.enableRotate = true;
controls.minDistance = 1; // controls.minDistance = 1;
// 4545 //
// 4545 controls.minPolarAngle = Math.PI / 4;
controls.minPolarAngle = Math.PI / 4; // 45 (π/4) controls.maxPolarAngle = (Math.PI * 3) / 4;
controls.maxPolarAngle = (Math.PI * 3) / 4; // 45 (3π/4)
const loader = new GLTFLoader(); const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader(); const dracoLoader = new DRACOLoader();
@ -137,15 +139,28 @@ loader.load(
async (gltf: any) => { async (gltf: any) => {
console.log('文件下载完成,开始解析模型...'); console.log('文件下载完成,开始解析模型...');
// //
const mergedMeshes: any[] = [];
gltf.scene.traverse((child: any) => { gltf.scene.traverse((child: any) => {
if (child.isMesh) { if (child.isMesh) {
// //
child.frustumCulled = true; // child.frustumCulled = true;
if (child.material) { if (child.material) {
// //
child.material.side = 0; // FrontSide - child.material.side = 0;
child.material.needsUpdate = true;
//
if (child.material.map) {
child.material.map.minFilter = THREE.LinearMipMapLinearFilter;
child.material.map.magFilter = THREE.LinearFilter;
}
} }
// 使
mergedMeshes.push(child);
} }
}); });
@ -160,7 +175,8 @@ loader.load(
} }
const loadTime = Date.now() - startTime; const loadTime = Date.now() - startTime;
console.log(`大场景模型完全加载并显示,总耗时: ${loadTime}ms`); console.log(`大场景模型完全加载并显示,总耗时:${loadTime}ms`);
console.log(`模型网格数量:${mergedMeshes.length}`);
}, },
// //
(xhr) => { (xhr) => {
@ -188,14 +204,17 @@ nextTick(() => {
} }
}); });
// //
const rgbELoader = new RGBELoader().load( setTimeout(() => {
'/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr', const rgbELoader = new RGBELoader().load(
(envMap: any) => { '/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
envMap.mapping = EquirectangularReflectionMapping; (envMap: any) => {
scene.environment = envMap; envMap.mapping = EquirectangularReflectionMapping;
} scene.environment = envMap;
); console.log('环境贴图加载完成');
}
);
}, 500); // 500ms
// //
const timeline1 = gsap.timeline(); const timeline1 = gsap.timeline();
@ -242,7 +261,8 @@ function handleResize() {
function init() { function init() {
requestAnimationFrame(init); requestAnimationFrame(init);
controls.update(); //
// controls.update(); //
render.render(scene, camera); render.render(scene, camera);
} }

@ -1,4 +1,5 @@
<template> <template>
<!-- <el-button @click="ccc">Default</el-button> -->
<el-card class="card"> <el-card class="card">
<el-scrollbar height="100%"> <el-scrollbar height="100%">
<h2 class="cardHead">运行信息</h2> <h2 class="cardHead">运行信息</h2>
@ -182,6 +183,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ElButton } from 'element-plus';
import { computed, ref, watch, onMounted } from 'vue'; import { computed, ref, watch, onMounted } from 'vue';
let dialogTableVisible = ref(false); let dialogTableVisible = ref(false);
@ -210,9 +212,22 @@ const props = defineProps({
isSwitch: { isSwitch: {
type: Boolean, type: Boolean,
default: true default: true
},
testStr: {
type: String,
default: ''
},
definitionItemJson: {
type: Object as any,
default: () => ({})
} }
}); });
console.log('传递:', props.definitionItemJson);
function ccc() {
props.definitionItemJson.props.testStr = 'aaaaaa';
}
const activities = [ const activities = [
{ {
content: '灭火允许', content: '灭火允许',

@ -1,87 +1,5 @@
<template> <template>
<!-- 四遥遥信 --> <!-- 四遥遥信 -->
<!-- <div style="display: flex; gap: 10px; align-items: center">
<el-popover
:width="300"
popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;"
>
<template #reference>
<el-icon
:class="['iconStyle', isAalarm ? 'blink-animation' : '']"
:size="22"
:style="{ color: isBool ? 'rgb(146, 252, 40)' : 'rgb(252, 40, 40)' }"
>
<WarningFilled />
</el-icon>
</template>
<template #default>
<div class="demo-rich-conent" style="display: flex; gap: 20px; flex-direction: column">
<el-icon
class="iconStyle"
:size="60"
:style="{ color: isBool ? 'rgb(146, 252, 40)' : 'rgb(252, 40, 40)' }"
>
<WarningFilled />
</el-icon>
<el-row :gutter="6">
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="绑定ID" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ moduleId }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="12" class="elColInfo">
<el-statistic title="节点名称" :value="null">
<template #suffix>
<el-tag size="default" type="success">{{ modeName }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="类型" :value="null">
<template #suffix>
<el-tag size="default" type="primary">遥信</el-tag>
</template>
</el-statistic>
</el-col>
</el-row>
<el-row :gutter="6">
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="开关情况" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ isBool }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="12" class="elColInfo">
<el-statistic title="告警" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ isAalarm }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="是否可告警" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ isAlarmable }}</el-tag>
</template>
</el-statistic>
</el-col>
</el-row>
</div>
</template>
</el-popover>
<el-tag type="primary">{{ modeName }}</el-tag>
</div> -->
<!-- <button @click="console.log('data:', nodeByModelsStore.nodeMap)">点击</button> --> <!-- <button @click="console.log('data:', nodeByModelsStore.nodeMap)">点击</button> -->
<el-row v-if="location === 'top'"> <el-row v-if="location === 'top'">
<el-col :span="24" class="flex-center"> <el-col :span="24" class="flex-center">
@ -106,7 +24,7 @@
<div style="display: flex; gap: 10px; align-items: center"> <div style="display: flex; gap: 10px; align-items: center">
<el-popover <el-popover
:width="300" :width="300"
:disabled="false" :disabled="showInfo"
popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;" popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;"
> >
<!-- :style="{ color: isBool ? 'rgb(146, 252, 40)' : 'rgb(252, 40, 40)' }" --> <!-- :style="{ color: isBool ? 'rgb(146, 252, 40)' : 'rgb(252, 40, 40)' }" -->
@ -226,7 +144,6 @@ onUnmounted(() => {
emitter.off(props.definitionItemJson.id); emitter.off(props.definitionItemJson.id);
}); });
// const props = defineProps(['definitionItemJson']);
const props = defineProps({ const props = defineProps({
moduleType: { moduleType: {
@ -241,6 +158,10 @@ const props = defineProps({
type: Object, type: Object,
default: () => ({}) default: () => ({})
}, },
showInfo: {
type: Boolean,
default: false
},
location: { location: {
type: String, type: String,
default: 'bottom' default: 'bottom'
@ -286,24 +207,6 @@ function loadingModuleById() {
} }
} }
// function loadingModuleById() {
// const globalData = (window as any).globalData as Map<string, any>;
// if (
// props.moduleId !== '' &&
// props.moduleId !== undefined &&
// props.moduleId !== '--' &&
// globalData?.has(props.moduleId)
// ) {
// let module = globalData.get(props.moduleId);
// if (module) {
// modeName.value = module.node.name;
// isBool.value = module.double == 1;
// isAalarm.value = module.alarm;
// isAlarmable.value = module.alarmable;
// }
// }
// }
// //
emitter.on(props.definitionItemJson.id, (value) => { emitter.on(props.definitionItemJson.id, (value) => {
console.log('触发事件', value); console.log('触发事件', value);

Loading…
Cancel
Save