开发消防

dev_xq_0.0.1
谢庆 2 weeks ago
parent 3105f0276e
commit c3950561f9

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

@ -46,6 +46,18 @@ import VueThreeGroundFloor from '@/components/vue-xq-test/vue-three-groundFloor.
import vueThreeEquipment from '@/components/three-components/vue-three-equipment.vue'; import vueThreeEquipment from '@/components/three-components/vue-three-equipment.vue';
import vueThreeFireControl from '@/components/three-components/vue-three-fire-control.vue'; import vueThreeFireControl from '@/components/three-components/vue-three-fire-control.vue';
import vueThreeSubstation from '@/components/three-components/vue-three-substation.vue'; import vueThreeSubstation from '@/components/three-components/vue-three-substation.vue';
import vueThreeTransformer from '@/components/three-components/vue-three-transformer.vue';
import VueNitrogenInjection from '@/components/vue-xq-test/vue-nitrogen-injection.vue';
import VueThreeNitrogen from '@/components/three-components/vue-three-nitrogen.vue';
import VueTableNitrogen from '@/components/vue-components/vue-table-nitrogen.vue';
import VueFlowChart from '@/components/vue-components/vue-flow-chart.vue';
import VueInfoDetector from '@/components/vue-components/vue-info-detector.vue';
import VueTableFireHydrant from '@/components/vue-components/vue-table-fire-hydrant.vue';
import VueTableFireHydrantInfo from '@/components/vue-components/vue-table-fire-hydrant-info.vue';
import VueThreeBuilding from '@/components/three-components/vue-three-building.vue';
import VueExtinguisherTable from '@/components/vue-components/vue-extinguisher-table.vue';
// F:\vue\workspace\maotu-webtopo\src\components\vue-components\vue-illumination-table.vue
import VueIlluminationTable from '@/components/vue-components/vue-illumination-table.vue';
// //
import VueGradeGauge from '@/components/vue-components/echarts-grade-gauge.vue'; import VueGradeGauge from '@/components/vue-components/echarts-grade-gauge.vue';
@ -58,7 +70,6 @@ import VueGuagePieChart from '@/components/vue-components/echarts-pie-chart.vue'
import VueSignalMonitoring from '@/components/vue-components/vue-signal-monitoring.vue'; import VueSignalMonitoring from '@/components/vue-components/vue-signal-monitoring.vue';
import VueImgImmobilization from '@/components/vue-components/vue-img-immobilization.vue'; import VueImgImmobilization from '@/components/vue-components/vue-img-immobilization.vue';
const instance = getCurrentInstance(); const instance = getCurrentInstance();
instance?.appContext.app.component('vue-my-button', VueMyButton); instance?.appContext.app.component('vue-my-button', VueMyButton);
instance?.appContext.app.component('vue-my-input', VueMyTest); instance?.appContext.app.component('vue-my-input', VueMyTest);
@ -89,6 +100,18 @@ instance?.appContext.app.component('vue-my-three-test', VueThreeTest);
instance?.appContext.app.component('vue-my-three-ground-floor', VueThreeGroundFloor); instance?.appContext.app.component('vue-my-three-ground-floor', VueThreeGroundFloor);
instance?.appContext.app.component('vue-my-three-fire-control', vueThreeFireControl); instance?.appContext.app.component('vue-my-three-fire-control', vueThreeFireControl);
instance?.appContext.app.component('vue-my-three-substation', vueThreeSubstation); instance?.appContext.app.component('vue-my-three-substation', vueThreeSubstation);
instance?.appContext.app.component('vue-my-three-transformer', vueThreeTransformer);
instance?.appContext.app.component('vue-my-nitrogen-injection', VueNitrogenInjection);
instance?.appContext.app.component('vue-my-three-nitrogen', VueThreeNitrogen);
instance?.appContext.app.component('vue-my-table-nitrogen', VueTableNitrogen);
instance?.appContext.app.component('vue-my-flow-chart', VueFlowChart);
instance?.appContext.app.component('vue-my-info-detector', VueInfoDetector);
instance?.appContext.app.component('vue-my-table-fire-hydrant', VueTableFireHydrant);
instance?.appContext.app.component('vue-my-table-fire-hydrant-info', VueTableFireHydrantInfo);
instance?.appContext.app.component('vue-my-three-building', VueThreeBuilding);
instance?.appContext.app.component('vue-my-extinguisher-table', VueExtinguisherTable);
instance?.appContext.app.component('vue-my-illumination-table', VueIlluminationTable);
instance?.appContext.app.component('vue-grade-gauge', VueGradeGauge); instance?.appContext.app.component('vue-grade-gauge', VueGradeGauge);
instance?.appContext.app.component('vue-guage-line-chart', VueGuageLineChart); instance?.appContext.app.component('vue-guage-line-chart', VueGuageLineChart);
instance?.appContext.app.component('vue-guage-bar-chart', VueGuageBarChart); instance?.appContext.app.component('vue-guage-bar-chart', VueGuageBarChart);
@ -96,7 +119,6 @@ instance?.appContext.app.component('vue-guage-pie-chart', VueGuagePieChart);
instance?.appContext.app.component('vue-img-immobilization', VueImgImmobilization); instance?.appContext.app.component('vue-img-immobilization', VueImgImmobilization);
instance?.appContext.app.component('vue-signal-monitoring', VueSignalMonitoring); instance?.appContext.app.component('vue-signal-monitoring', VueSignalMonitoring);
// instance?.appContext.app.component('vue-my-grade-gauge', VueGradeGauge); // instance?.appContext.app.component('vue-my-grade-gauge', VueGradeGauge);
const electrical_modules_files = import.meta.glob('./assets/svgs/electrical/**.svg', { const electrical_modules_files = import.meta.glob('./assets/svgs/electrical/**.svg', {
@ -763,6 +785,45 @@ leftAsideStore.registerConfig('vue3D组件', [
val: '--' val: '--'
} }
} }
},
{
id: 'vue-my-three-transformer',
title: '3d-变压器',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
dataSource: {
title: '数据源',
type: 'input',
val: '--'
}
}
},
{
id: 'vue-my-three-nitrogen',
title: '3d-排油注氮',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
dataSource: {
title: '数据源',
type: 'input',
val: '--'
}
}
},
{
id: 'vue-my-three-building',
title: '3d-一楼',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
dataSource: {
title: '数据源',
type: 'input',
val: '--'
}
}
} }
]); ]);
@ -996,6 +1057,268 @@ leftAsideStore.registerConfig('vue组件', [
title: '标题' title: '标题'
} }
} }
},
{
id: 'vue-my-nitrogen-injection',
title: '变压器排油注氮灭火-光字牌',
type: 'vue',
thumbnail: '/svgs/table-base.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: 'Segoe UI',
options: [
{
value: 'Segoe UI',
label: 'Segoe UI'
},
{
value: '微软雅黑',
label: '微软雅黑'
},
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#000000',
title: '文字颜色'
}
}
},
{
id: 'vue-my-table-nitrogen',
title: '2号主变排油灭氮-运行信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-info-detector',
title: '2号主变排油灭氮-火灾探测器基本信息',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-flow-chart',
title: '2号主变排油灭氮-操作流程',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-table-fire-hydrant',
title: '消火栓系统-运行信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-table-fire-hydrant-info',
title: '消火栓系统-消火栓信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-extinguisher-table',
title: '灭火器配置-灭火器信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
}
}
},
{
id: 'vue-my-illumination-table',
title: '消防应急-运行信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
}
}
} }
]); ]);

@ -65,7 +65,6 @@
<el-sub-menu <el-sub-menu
:index="menu.children[0].name" :index="menu.children[0].name"
v-if="menu.children && menu.children.length > 1" v-if="menu.children && menu.children.length > 1"
@click="handleSubMenuClick(menu.children[0])"
> >
<template #title> <template #title>
<el-icon> <el-icon>
@ -113,6 +112,7 @@ const props = withDefaults(
function isStairRoute(routeName: string) { function isStairRoute(routeName: string) {
if (stairRouteNames.includes(routeName)) { if (stairRouteNames.includes(routeName)) {
console.log('getStairRoute:', routeName);
emitter.emit('getStairRoute', routeName); emitter.emit('getStairRoute', routeName);
} }
} }
@ -120,6 +120,7 @@ function isStairRoute(routeName: string) {
const router = useRouter(); const router = useRouter();
function headerCliek(val: any) { function headerCliek(val: any) {
console.log('node01:', val.index);
if (stairRouteNames.includes(val.index)) { if (stairRouteNames.includes(val.index)) {
isStairRoute(val.index); isStairRoute(val.index);
} else { } else {
@ -136,7 +137,17 @@ function headerCliek(val: any) {
} }
function handleSubMenuTitleClick(menu: any) { function handleSubMenuTitleClick(menu: any) {
console.log('node02:', menu.name);
if (stairRouteNames.includes(menu.name)) {
isStairRoute(menu.name); isStairRoute(menu.name);
} else {
stairRouteChildrenMap.forEach((children: string[], parent: string) => {
if (children.includes(menu.name)) {
isStairRoute(parent);
}
});
}
// //
router.push({ router.push({
name: menu.name, name: menu.name,
@ -146,6 +157,7 @@ function handleSubMenuTitleClick(menu: any) {
// //
function handleSubMenuClick(menu: any) { function handleSubMenuClick(menu: any) {
console.log('node03:', menu.name);
if (stairRouteNames.includes(menu.name)) { if (stairRouteNames.includes(menu.name)) {
isStairRoute(menu.name); isStairRoute(menu.name);
// //

@ -163,7 +163,7 @@ import SvgAnalysis from '@/components/mt-edit/components/svg-analysis/index.vue'
import { blobToBase64 } from '@/components/mt-edit/utils'; import { blobToBase64 } from '@/components/mt-edit/utils';
function viewGload() { function viewGload() {
console.log("xxx:",globalStore); console.log('xxx:', globalStore);
} }
type RightAsideProps = { type RightAsideProps = {

@ -193,6 +193,7 @@ import JsonEdit from './json-edit.vue';
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { modelApi, BASE_URL } from '@/utils/request'; import { modelApi, BASE_URL } from '@/utils/request';
import imageModel from '@/components/mt-edit/components/layout/base-panel/imageModel.vue'; import imageModel from '@/components/mt-edit/components/layout/base-panel/imageModel.vue';
import { globalStore } from '@/components/mt-edit/store/global';
type SelectItemPropsSettingProps = { type SelectItemPropsSettingProps = {
propsInfo: ILeftAsideConfigItemPublicProps | undefined; propsInfo: ILeftAsideConfigItemPublicProps | undefined;
}; };
@ -258,9 +259,11 @@ function handleIconClick(obj: any) {
let attrImg: any; let attrImg: any;
// //
const onImageDialog = (obj: any) => { const onImageDialog = (obj: any) => {
console.log('xxxxx:', obj);
dialogImageVisible.value = true; dialogImageVisible.value = true;
attrImg = obj; attrImg = obj;
}; };
function bindingImg(obj: any) { function bindingImg(obj: any) {
console.log('绑定图片', obj, attrImg); console.log('绑定图片', obj, attrImg);
attrImg.val = obj.id; attrImg.val = obj.id;

@ -0,0 +1,190 @@
<template>
<div class="container">
<!-- 排油注氮 -->
<!-- 3D 场景 -->
<div class="div3D" ref="div3D" v-show="show3D"></div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
// threejs
import {
AxesHelper,
Color,
PerspectiveCamera,
Scene,
WebGLRenderer,
EquirectangularReflectionMapping,
Group
} from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
const div3D = ref<HTMLDivElement>();
//
const scene = new Scene();
//
const show3D = ref(true);
//
const camera = new PerspectiveCamera(
25,
div3D.value?.clientWidth! / div3D.value?.clientHeight!,
0.05,
1000
); // 1
camera.position.set(0, 14, 13.5);
camera.lookAt(0, 0, 0);
scene.add(camera);
//
const render = new WebGLRenderer({ antialias: true }); // 齿
render.setClearColor(new Color('#131519'));
//
const controls = new OrbitControls(camera, render.domElement);
//
// controls.enableZoom = false;
// controls.autoRotate = false;
// controls.enablePan = false; //
controls.autoRotateSpeed = 1;
controls.dampingFactor = 0.2;
controls.rotateSpeed = 0.3; // 1.0
controls.enableDamping = true;
controls.enableRotate = true;
controls.minDistance = 1; //
// 4545
// 4545
controls.minPolarAngle = Math.PI / 4; // 45 (π/4)
controls.maxPolarAngle = (Math.PI * 3) / 4; // 45 (3π/4)
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader);
let meshArr: Group[] = [];
// F:\vue\workspace\maotu-webtopo\public\models\complexBuilding\complexBuilding.gltf
loader.load('/models/complexBuilding/complexBuilding.gltf', (gltf: any) => {
gltf.scene.position.y = -6;
scene.add(gltf.scene);
});
//
const rgbELoader = new RGBELoader().load(
'/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
(envMap: any) => {
envMap.mapping = EquirectangularReflectionMapping;
scene.environment = envMap;
}
);
//
// const axes = new AxesHelper(20);
// scene.add(axes);
//
function handleResize() {
if (!div3D.value) return;
const container = div3D.value;
const width = container.clientWidth;
const height = container.clientHeight;
//
camera.aspect = width / height;
camera.updateProjectionMatrix();
//
render.setSize(width, height);
}
function init() {
requestAnimationFrame(init);
controls.update();
render.render(scene, camera);
}
onMounted(() => {
//
handleResize();
//
init();
//
div3D.value?.appendChild(render.domElement);
//
const resizeObserver = new ResizeObserver(handleResize);
if (div3D.value) {
resizeObserver.observe(div3D.value);
}
// 便
(window as any)._resizeObserver = resizeObserver;
});
onUnmounted(() => {
//
if ((window as any)._resizeObserver) {
(window as any)._resizeObserver.disconnect();
delete (window as any)._resizeObserver;
}
});
</script>
<style scoped>
.container {
width: 100%;
height: 100%;
position: relative;
}
.div3D {
width: 100%;
height: 100%;
position: relative;
}
.principle-diagram {
position: absolute;
top: 10%;
right: 0;
width: 45%;
height: 45%;
z-index: 50;
display: flex;
justify-content: center;
align-items: center;
/* transition: all 0.3s ease; */
}
/* 只显示原理图时的样式 */
.principle-diagram.principle-only {
top: 0;
right: 0;
width: 100%;
height: 100%;
border-radius: 0;
box-shadow: none;
}
.principle-img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.control-buttons {
position: absolute;
top: 2%;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: row;
gap: 0.5%;
z-index: 100;
}
</style>

@ -0,0 +1,190 @@
<template>
<div class="container">
<!-- 排油注氮 -->
<!-- 3D 场景 -->
<div class="div3D" ref="div3D" v-show="show3D"></div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
// threejs
import {
AxesHelper,
Color,
PerspectiveCamera,
Scene,
WebGLRenderer,
EquirectangularReflectionMapping,
Group
} from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
const div3D = ref<HTMLDivElement>();
//
const scene = new Scene();
//
const show3D = ref(true);
//
const camera = new PerspectiveCamera(
25,
div3D.value?.clientWidth! / div3D.value?.clientHeight!,
0.05,
1000
); // 1
camera.position.set(10, 10, -35);
camera.lookAt(0, 0, 0);
scene.add(camera);
//
const render = new WebGLRenderer({ antialias: true }); // 齿
render.setClearColor(new Color('#131519'));
//
const controls = new OrbitControls(camera, render.domElement);
//
// controls.enableZoom = false;
// controls.autoRotate = false;
// controls.enablePan = false; //
controls.autoRotateSpeed = 1;
controls.dampingFactor = 0.2;
controls.rotateSpeed = 0.3; // 1.0
controls.enableDamping = true;
controls.enableRotate = true;
controls.minDistance = 1; //
// 4545
// 4545
controls.minPolarAngle = Math.PI / 4; // 45 (π/4)
controls.maxPolarAngle = (Math.PI * 3) / 4; // 45 (3π/4)
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader);
let meshArr: Group[] = [];
// F:\vue\workspace\maotu-webtopo\public\models\nitrogenInjection\nitrogenInjection.bin
loader.load('/models/nitrogenInjection/nitrogenInjection.gltf', (gltf: any) => {
gltf.scene.position.y = -6;
scene.add(gltf.scene);
});
//
const rgbELoader = new RGBELoader().load(
'/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
(envMap: any) => {
envMap.mapping = EquirectangularReflectionMapping;
scene.environment = envMap;
}
);
//
// const axes = new AxesHelper(20);
// scene.add(axes);
//
function handleResize() {
if (!div3D.value) return;
const container = div3D.value;
const width = container.clientWidth;
const height = container.clientHeight;
//
camera.aspect = width / height;
camera.updateProjectionMatrix();
//
render.setSize(width, height);
}
function init() {
requestAnimationFrame(init);
controls.update();
render.render(scene, camera);
}
onMounted(() => {
//
handleResize();
//
init();
//
div3D.value?.appendChild(render.domElement);
//
const resizeObserver = new ResizeObserver(handleResize);
if (div3D.value) {
resizeObserver.observe(div3D.value);
}
// 便
(window as any)._resizeObserver = resizeObserver;
});
onUnmounted(() => {
//
if ((window as any)._resizeObserver) {
(window as any)._resizeObserver.disconnect();
delete (window as any)._resizeObserver;
}
});
</script>
<style scoped>
.container {
width: 100%;
height: 100%;
position: relative;
}
.div3D {
width: 100%;
height: 100%;
position: relative;
}
.principle-diagram {
position: absolute;
top: 10%;
right: 0;
width: 45%;
height: 45%;
z-index: 50;
display: flex;
justify-content: center;
align-items: center;
/* transition: all 0.3s ease; */
}
/* 只显示原理图时的样式 */
.principle-diagram.principle-only {
top: 0;
right: 0;
width: 100%;
height: 100%;
border-radius: 0;
box-shadow: none;
}
.principle-img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.control-buttons {
position: absolute;
top: 2%;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: row;
gap: 0.5%;
z-index: 100;
}
</style>

@ -85,6 +85,7 @@ const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader(); const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader); loader.setDRACOLoader(dracoLoader);
let meshArr: Group[] = []; let meshArr: Group[] = [];
// public\models\nitrogenInjection\nitrogenInjection.gltf
loader.load('/models/substation/substation.gltf', (gltf: any) => { loader.load('/models/substation/substation.gltf', (gltf: any) => {
scene.add(gltf.scene); scene.add(gltf.scene);
const loadTime = Date.now() - startTime; const loadTime = Date.now() - startTime;

@ -0,0 +1,230 @@
<template>
<div class="container">
<!-- 3D 场景 -->
<div class="div3D" ref="div3D" v-show="show3D"></div>
<!-- 原理图 -->
<div
class="principle-diagram"
v-if="showPrinciple"
:class="{ 'principle-only': showPrincipleOnly }"
>
<img src="/models/transformer/yuanli.png" alt="原理图" class="principle-img" />
</div>
</div>
<!-- 固定位置的控制按钮 -->
<div class="control-buttons">
<el-button type="primary" @click="toggle3D"></el-button>
<el-button type="primary" @click="togglePrinciple"></el-button>
<el-button type="primary" @click="showBoth"></el-button>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
// threejs
import {
AxesHelper,
Color,
PerspectiveCamera,
Scene,
WebGLRenderer,
EquirectangularReflectionMapping,
Group
} from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
const div3D = ref<HTMLDivElement>();
//
const scene = new Scene();
//
const show3D = ref(true);
const showPrinciple = ref(false);
const showPrincipleOnly = ref(false); //
//
const toggle3D = () => {
console.log('点击三维图切换');
show3D.value = true;
showPrinciple.value = false;
showPrincipleOnly.value = false;
console.log('show3D:', show3D.value, 'showPrinciple:', showPrinciple.value);
};
const togglePrinciple = () => {
console.log('点击原理图切换');
showPrinciple.value = true;
show3D.value = false;
showPrincipleOnly.value = true;
console.log('show3D:', show3D.value, 'showPrinciple:', showPrinciple.value);
};
const showBoth = () => {
show3D.value = true;
showPrinciple.value = true;
showPrincipleOnly.value = false;
};
//
const camera = new PerspectiveCamera(
25,
div3D.value?.clientWidth! / div3D.value?.clientHeight!,
0.05,
1000
); // 1
camera.position.set(35, 10, 20);
camera.lookAt(0, 0, 0);
scene.add(camera);
//
const render = new WebGLRenderer({ antialias: true }); // 齿
render.setClearColor(new Color('#131519'));
//
const controls = new OrbitControls(camera, render.domElement);
//
// controls.enableZoom = false;
// controls.autoRotate = false;
// controls.enablePan = false; //
controls.autoRotateSpeed = 1;
controls.dampingFactor = 0.2;
controls.rotateSpeed = 0.3; // 1.0
controls.enableDamping = true;
controls.enableRotate = true;
controls.minDistance = 1; //
// 4545
// 4545
controls.minPolarAngle = Math.PI / 4; // 45 (π/4)
controls.maxPolarAngle = (Math.PI * 3) / 4; // 45 (3π/4)
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader);
let meshArr: Group[] = [];
loader.load('/models/transformer/transformer.gltf', (gltf: any) => {
gltf.scene.position.y = -3;
scene.add(gltf.scene);
});
//
const rgbELoader = new RGBELoader().load(
'/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
(envMap: any) => {
envMap.mapping = EquirectangularReflectionMapping;
scene.environment = envMap;
}
);
//
// const axes = new AxesHelper(20);
// scene.add(axes);
//
function handleResize() {
if (!div3D.value) return;
const container = div3D.value;
const width = container.clientWidth;
const height = container.clientHeight;
//
camera.aspect = width / height;
camera.updateProjectionMatrix();
//
render.setSize(width, height);
}
function init() {
requestAnimationFrame(init);
controls.update();
render.render(scene, camera);
}
onMounted(() => {
//
handleResize();
//
init();
//
div3D.value?.appendChild(render.domElement);
//
const resizeObserver = new ResizeObserver(handleResize);
if (div3D.value) {
resizeObserver.observe(div3D.value);
}
// 便
(window as any)._resizeObserver = resizeObserver;
});
onUnmounted(() => {
//
if ((window as any)._resizeObserver) {
(window as any)._resizeObserver.disconnect();
delete (window as any)._resizeObserver;
}
});
</script>
<style scoped>
.container {
width: 100%;
height: 100%;
position: relative;
}
.div3D {
width: 100%;
height: 100%;
position: relative;
}
.principle-diagram {
position: absolute;
top: 10%;
right: 0;
width: 45%;
height: 45%;
z-index: 50;
display: flex;
justify-content: center;
align-items: center;
/* transition: all 0.3s ease; */
}
/* 只显示原理图时的样式 */
.principle-diagram.principle-only {
top: 0;
right: 0;
width: 100%;
height: 100%;
border-radius: 0;
box-shadow: none;
}
.principle-img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.control-buttons {
position: absolute;
top: 2%;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: row;
gap: 0.5%;
z-index: 100;
}
</style>

@ -0,0 +1,305 @@
<template>
<div class="table-container">
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">运行信息</h2>
<div class="table-wrapper" v-loading="tableArr.length === 0">
<!-- :span-method="objectSpanMethods" -->
<el-table
:data="tableArr"
style="width: 100%"
:span-method="objectSpanMethods"
class="full-height-table"
>
<el-table-column prop="floorArea" label="所在区域" />
<el-table-column prop="equipmentPlace" label="配置地点" />
<el-table-column prop="equipmentName" label="设备名称" />
<el-table-column prop="equipmentSpecification" label="规格型号" />
<el-table-column prop="equipmentNumber" label="编号" />
<el-table-column prop="vender" label="设备厂家" />
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import type { TableColumnCtx } from 'element-plus';
import { computed, onMounted, onUnmounted, ref, watch, reactive } from 'vue';
import emitter from '@/utils/emitter';
import { ro } from 'element-plus/es/locales.mjs';
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
interface Equipment {
equipmentPlace: string; //
equipmentName: string; //
equipmentSpecification: string; //
equipmentNumber: string; //
vender: string; //
}
interface FloorObj {
floorArea: string; //
equipments: Equipment[];
}
let tableArr = ref<any[]>([]);
let spanMap = ref<Map<string, number>>(new Map<string, number>());
//
async function dataInit() {
floorData.forEach((floor) => {
floor.equipments.forEach((equipment) => {
tableArr.value.push({
floorArea: floor.floorArea,
equipmentPlace: equipment.equipmentPlace,
equipmentName: equipment.equipmentName,
equipmentSpecification: equipment.equipmentSpecification,
equipmentNumber: equipment.equipmentNumber,
vender: equipment.vender
});
});
if (!spanMap.value.has(floor.floorArea))
spanMap.value.set(floor.floorArea, floor.equipments.length);
});
console.log('spanMap', spanMap.value);
}
//
let floorStartIndex = ref<Map<string, number>>(new Map<string, number>());
//
function objectSpanMethods({ rowIndex, columnIndex }: any) {
if (columnIndex === 0) {
// ""
const floorArea = tableArr.value[rowIndex].floorArea;
//
if (!floorStartIndex.value.has(floorArea)) {
floorStartIndex.value.set(floorArea, rowIndex);
}
//
if (floorStartIndex.value.get(floorArea) === rowIndex) {
return [spanMap.value.get(floorArea) || 1, 1];
} else {
//
return [0, 0];
}
}
return [1, 1];
}
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//
const floorData: FloorObj[] = [
{
floorArea: '生产综合楼1楼',
equipments: [
{
equipmentPlace: '蓄电池室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '220kV保护室',
equipmentName: '氧化碳灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '380V配电室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '35kV高压室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '2号接地变室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '110kV电缆室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '2号站用变室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '生产综合楼1楼走廊',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
}
]
},
{
floorArea: '生产综合楼2楼',
equipments: [
{
equipmentPlace: '110kVGIS室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '110kV保护室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '主控制室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '生产综合楼2楼',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
}
]
}
];
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -0,0 +1,174 @@
<template>
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">操作流程</h2>
<div class="cardBody">
<el-steps
style="max-width: 100%"
:active="4"
align-center
direction="vertical"
finish-status="success"
>
<el-step description="变压器故障起火" />
<el-step>
<template #description>
保护动作
<div class="parallel-box">
<el-tag type="primary">重瓦斯动作</el-tag>
<el-tag type="success">温控器动作</el-tag>
<el-tag type="primary">压力释放动作</el-tag>
<el-tag type="primary">火灾探测器动作</el-tag>
</div>
</template>
</el-step>
<el-step description="排油阀开启" />
<el-step description="注氮阀开启" />
<el-step description="注氮阀关闭" />
<el-step description="注氮 10 分钟以上达到防爆灭火效果" />
</el-steps>
</div>
<div class="button-group">
<el-button type="primary" size="small">手动启动</el-button>
<el-button type="primary" size="small">手动停止</el-button>
<el-button type="primary" size="small">紧急停止</el-button>
</div>
</el-card>
</template>
<script setup lang="ts"></script>
<style scoped>
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.cardBody {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
overflow-y: auto;
}
/* 并行步骤框 */
.parallel-box {
display: flex;
flex-direction: column;
gap: 15px;
margin-top: 15px;
margin-bottom: 15px;
}
/* el-tag 样式调整 */
.parallel-box :deep(.el-tag) {
text-align: left;
padding: 8px 16px;
width: 60%;
}
/* 并行步骤样式 */
.parallel-steps {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 10px;
padding: 10px;
background: rgba(255, 255, 255, 0.05);
border-radius: 6px;
}
/* 按钮组样式 */
.button-group {
display: flex;
gap: 1%;
justify-content: center;
margin-top: 15px;
}
.step-item {
padding: 8px 12px;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: #ffffff;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
text-align: center;
}
.step-title {
font-weight: bold;
font-size: 14px;
}
/* 操作区域 */
.operation-area {
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
padding: 15px;
background: rgba(255, 255, 255, 0.05);
margin-top: 20px;
}
.area-title {
margin: 0 0 15px 0;
font-size: 14px;
font-weight: bold;
color: #4facfe;
text-align: center;
}
.buttons {
display: flex;
gap: 15px;
justify-content: center;
margin-bottom: 15px;
}
.notes {
display: flex;
justify-content: space-between;
gap: 20px;
}
.note {
margin: 0;
font-size: 11px;
color: #f5576c;
line-height: 1.6;
flex: 1;
}
.note-label {
font-weight: bold;
color: #f093fb;
}
/* 响应式 */
@media (max-width: 768px) {
.notes {
flex-direction: column;
}
}
</style>

@ -0,0 +1,305 @@
<template>
<div class="table-container">
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">运行信息</h2>
<div class="table-wrapper" v-loading="tableArr.length === 0">
<!-- :span-method="objectSpanMethods" -->
<el-table
:data="tableArr"
style="width: 100%"
:span-method="objectSpanMethods"
class="full-height-table"
>
<el-table-column prop="floorArea" label="所在区域" />
<el-table-column prop="equipmentPlace" label="设备地点" />
<el-table-column prop="fireproofDoor" label="防火门" />
<el-table-column prop="indicate" label="疏散指示" />
<el-table-column prop="illumination" label="应急照明" />
<el-table-column prop="control" label="应急照明控制" />
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import type { TableColumnCtx } from 'element-plus';
import { computed, onMounted, onUnmounted, ref, watch, reactive } from 'vue';
import emitter from '@/utils/emitter';
import { ro } from 'element-plus/es/locales.mjs';
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
interface Equipment {
equipmentPlace: string; //
fireproofDoor: string; //
indicate: string; //
illumination: string; //
control: boolean; // true false
}
interface FloorObj {
floorArea: string; //
equipments: Equipment[];
}
let tableArr = ref<any[]>([]);
let spanMap = ref<Map<string, number>>(new Map<string, number>());
//
async function dataInit() {
floorData.forEach((floor) => {
floor.equipments.forEach((equipment) => {
tableArr.value.push({
floorArea: floor.floorArea,
equipmentPlace: equipment.equipmentPlace,
fireproofDoor: equipment.fireproofDoor,
indicate: equipment.indicate,
illumination: equipment.illumination,
control: equipment.control
});
});
if (!spanMap.value.has(floor.floorArea))
spanMap.value.set(floor.floorArea, floor.equipments.length);
});
console.log('spanMap', spanMap.value);
}
//
let floorStartIndex = ref<Map<string, number>>(new Map<string, number>());
//
function objectSpanMethods({ rowIndex, columnIndex }: any) {
if (columnIndex === 0) {
// ""
const floorArea = tableArr.value[rowIndex].floorArea;
//
if (!floorStartIndex.value.has(floorArea)) {
floorStartIndex.value.set(floorArea, rowIndex);
}
//
if (floorStartIndex.value.get(floorArea) === rowIndex) {
return [spanMap.value.get(floorArea) || 1, 1];
} else {
//
return [0, 0];
}
}
return [1, 1];
}
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//
const floorData: FloorObj[] = [
{
floorArea: '生产综合楼1楼',
equipments: [
{
equipmentPlace: '蓄电池室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '220kV保护室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '380V配电室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '110kV电缆室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '220kV保护室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '380V配电室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '35kV高压室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '2号接地变室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '2号站用变室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
}
]
},
{
floorArea: '生产综合楼2楼',
equipments: [
{
equipmentPlace: '110kVGIS室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '110kV保护室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '主控制室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
}
]
}
];
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -37,17 +37,12 @@ const props = defineProps({
} }
}); });
onUnmounted(() => { onUnmounted(() => {
console.log('组件卸载'); console.log('组件卸载');
}); });
// //
onMounted(() => { onMounted(() => {});
});
</script> </script>
<style scoped> <style scoped>

@ -0,0 +1,138 @@
<template>
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">火灾探测器基本信息</h2>
<div class="cardBody">
<el-row :gutter="20" style="height: 100%">
<el-col :span="12" class="image-col">
<img src="/imgs/xianqvan.png" style="width: 100%; height: 100%" />
</el-col>
<el-col :span="12">
<el-row class="info-row">
<el-col :span="10" class="info-label">厂家</el-col>
<el-col :span="12"><el-tag size="small">海湾公司</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">型号</el-col>
<el-col :span="12"><el-tag size="small">CTI-155X</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">投运日期</el-col>
<el-col :span="12"><el-tag size="small">2012-08-08</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">使用环境</el-col>
<el-col :span="12"><el-tag size="small">温度 -5~45</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">火灾响应规模</el-col>
<el-col :span="12"><el-tag size="small">10mm</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">测量温度精度</el-col>
<el-col :span="12"><el-tag size="small">1</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">定位精度</el-col>
<el-col :span="12"><el-tag size="small">1 </el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">类型</el-col>
<el-col :span="12"><el-tag size="small">定温式</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">报警温度</el-col>
<el-col :span="12"><el-tag size="small">85</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">标准</el-col>
<el-col :span="12"><el-tag size="small">GB16280-2014</el-tag></el-col>
</el-row>
</el-col>
</el-row>
</div>
</el-card>
</template>
<script setup lang="ts"></script>
<style scoped>
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.cardBody {
width: 100%;
height: 100%;
}
/* el-row 高度继承 */
.cardBody :deep(.el-row) {
/* height: 100%; */
}
/* el-col 高度继承 */
.cardBody :deep(.el-col) {
/* height: 100%;
display: flex;
align-items: stretch; */
}
/* 图片列样式 */
.image-col {
height: 100%;
display: flex;
}
/* 探测器图片样式 */
.detector-image {
width: 100%;
height: 100%;
object-fit: contain;
}
/* 信息行样式 */
.info-row {
margin-bottom: 2%;
}
/* 标签样式 */
.info-label {
font-size: 12px;
color: #ffffff;
}
/* el-tag 样式 */
.info-row :deep(.el-tag) {
font-size: 11px;
}
</style>

@ -0,0 +1,225 @@
<template>
<div class="table-container">
<!-- 2号主变 -->
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">消火栓信息</h2>
<div class="table-wrapper" v-loading="arr.length === 0">
<el-table
:data="arr"
style="width: 100%"
class="full-height-table"
@cell-click="handleCellClick"
>
<el-table-column prop="equipmentName" label="设备名称" />
<el-table-column prop="equipmentModel" label="规格型号" />
<el-table-column prop="equipmentPlace" label="设备位置" />
<el-table-column prop="manufacturers" label="厂家" />
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, onUnmounted } from 'vue';
import emitter from '@/utils/emitter';
//
/// <reference path="../../../global.d.ts" />
function handleCellClick(obj: any) {
console.log('点击:', obj);
emitter.emit('binding-obj-facility-move', obj.id);
}
emitter.on('binding-data-update', () => {
console.log('@@binding-data-update');
dataInit();
});
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
console.log('父传子itemjson:', props.definitionItemJson);
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
//
async function dataInit() {}
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//node
interface EquipmentNode {
equipmentName: string; //
equipmentModel: string; //
equipmentPlace: string; //
manufacturers: string; //
}
//
// equipmentState 0 1
// currentState 0 1 2 3 4 5 6 7
// operation true false null
const arr: EquipmentNode[] = [
{
equipmentName: '生产综合楼一楼消火栓1',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼一楼东走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼一楼消火栓2',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼一楼西走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼二楼消火栓1',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼二楼东走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼二楼消火栓2',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼二楼西走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼一楼消火栓1',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼一楼东走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼一楼消火栓2',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼一楼西走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼二楼消火栓1',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼二楼东走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼二楼消火栓2',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼二楼西走廊',
manufacturers: '宏达'
}
];
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -0,0 +1,264 @@
<template>
<div class="table-container">
<!-- 2号主变 -->
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">运行信息</h2>
<div class="table-wrapper" v-loading="arr.length === 0">
<el-table
:data="arr"
style="width: 100%"
class="full-height-table"
@cell-click="handleCellClick"
>
<el-table-column prop="equipmentName" label="设备名称" />
<el-table-column label="设备状态">
<template #default="{ row }">
<el-tag :type="row.equipmentState === 0 ? 'success' : 'warning'">
{{ row.equipmentState === 0 ? '正常' : '故障' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template #default="{ row }">
<el-tag type="primary">{{ row.currentState }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-tag v-if="row.operation == null || row.operation === ''" type="info"
>无操作</el-tag
>
<template v-else>
<el-button type="primary" size="small">开启</el-button>
<el-button type="primary" size="small">关闭</el-button>
</template>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, onUnmounted } from 'vue';
import emitter from '@/utils/emitter';
//
/// <reference path="../../../global.d.ts" />
function handleCellClick(obj: any) {
console.log('点击:', obj);
emitter.emit('binding-obj-facility-move', obj.id);
}
emitter.on('binding-data-update', () => {
console.log('@@binding-data-update');
dataInit();
});
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
console.log('父传子itemjson:', props.definitionItemJson);
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
//
async function dataInit() {}
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//node
interface EquipmentNode {
equipmentName: string; //
equipmentState: number; // 0 1
currentState: string; //
operation: boolean | null; // true false null
}
//
// equipmentState 0 1
// currentState 0 1 2 3 4 5 6 7
// operation true false null
const arr: EquipmentNode[] = [
{
equipmentName: '消防泵控制装置',
equipmentState: 0,
currentState: '运行',
operation: null
},
{
equipmentName: '消防泵主供电源供电',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '消防泵备用电源供电',
equipmentState: 0,
currentState: '开',
operation: true
},
{
equipmentName: '控制装置主供电源供电',
equipmentState: 0,
currentState: '开',
operation: true
},
{
equipmentName: '控制装置备用电源供电',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '深井泵',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '高压侧断路器',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '1号消防泵',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '2号消防泵',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '消防水池水位',
equipmentState: 0,
currentState: '80%',
operation: null
},
{
equipmentName: '管网压力',
equipmentState: 0,
currentState: '0.4Mpa',
operation: null
}
];
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -0,0 +1,378 @@
<template>
<div class="table-container">
<!-- 2号主变 -->
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">运行信息</h2>
<div class="table-wrapper" v-loading="arr.length === 0">
<el-table
:data="arr"
style="width: 100%"
class="full-height-table"
@cell-click="handleCellClick"
>
<el-table-column prop="equipmentName" label="设备名称" />
<el-table-column label="设备状态">
<template #default="{ row }">
<el-tag :type="row.equipmentState === 0 ? 'success' : 'warning'">
{{ row.equipmentState === 0 ? '正常' : '故障' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template #default="{ row }">
<el-tag v-if="row.currentState === 0" type="info"></el-tag>
<el-tag v-else-if="row.currentState === 1" type="danger">报警</el-tag>
<el-tag v-else-if="row.currentState === 2" type="success">动作</el-tag>
<el-tag v-else-if="row.currentState === 3" type="danger">分位</el-tag>
<el-tag v-else-if="row.currentState === 4" type="danger">关闭</el-tag>
<el-tag v-else-if="row.currentState === 5" type="primary">开启</el-tag>
<el-tag v-else-if="row.currentState === 6" type="primary">运行</el-tag>
<el-tag v-else-if="row.currentState === 7" type="primary">正常</el-tag>
<el-tag v-else type="info">未知状态</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-tag v-if="row.operation == null" type="info"></el-tag>
<el-button type="primary" class="operation-btn" v-else-if="row.operation">
屏蔽
</el-button>
<el-button type="primary" class="operation-btn" v-else-if="!row.operation">
取消屏蔽
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import type { TableColumnCtx } from 'element-plus';
import { ElMessage } from 'element-plus';
import { computed, onMounted, onUnmounted, ref, watch, reactive } from 'vue';
import { modelApi } from '@/utils/request';
import emitter from '@/utils/emitter';
const loading = ref(false);
//
/// <reference path="../../../global.d.ts" />
interface RecRuntimeData {
double: number;
node: {
name: string;
};
}
interface RecServiceType {
service: {
node: {
runtimes: Record<string, RecRuntimeData>;
};
};
}
interface ExtendedParentWindow extends Window {
Rec?: RecServiceType;
}
interface User {
id: string;
name: string;
amount1: string;
amount2: string;
amount3: number;
}
interface Equipment {
id: string; //ID
address?: string; //
name: string; //
eState: number; // 0 1
currentState: number; // 0 1 2
operation: boolean; // true false
}
interface FloorObj {
floorName: string; //
equipments: Equipment[];
}
// node
interface FloorNode {
roomId: string;
floorName: string;
eqpList: EquipmentNode[];
}
//node
// interface EquipmentNode {
// id: string; //ID
// name: string; //
// isBinding: boolean; //
// eState: number; // 0 1
// currentState: number; // 0 1 2
// operation: boolean; // true false
// }
function handleCellClick(obj: any) {
console.log('点击:', obj);
emitter.emit('binding-obj-facility-move', obj.id);
}
emitter.on('binding-data-update', () => {
console.log('@@binding-data-update');
dataInit();
});
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
console.log('父传子itemjson:', props.definitionItemJson);
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
// const arr = ref<any[]>([]);
let targetDataTable: FloorNode[] = [];
let initArrs: any = {};
//
async function dataInit() {}
//
const tableDatas = computed(() => {
return targetDataTable.flatMap((floor) =>
floor.eqpList.map((equipment) => ({
...equipment,
floorName: floor.floorName, //
roomId: floor.roomId //
}))
);
});
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//node
interface EquipmentNode {
equipmentName: string; //
equipmentState: number; // 0 1
currentState: number; // 0 1 2 3 4 5 6 7
operation: boolean | null; // true false null
}
//
// equipmentState 0 1
// currentState 0 1 2 3 4 5 6 7
// operation true false null
const arr: EquipmentNode[] = [
{
equipmentName: '火灾探测器1',
equipmentState: 0,
currentState: 1,
operation: true
},
{
equipmentName: '火灾探测器2',
equipmentState: 0,
currentState: 1,
operation: true
},
{
equipmentName: '火灾探测器3',
equipmentState: 1,
currentState: 0,
operation: false
},
{
equipmentName: '火灾探测器4',
equipmentState: 0,
currentState: 0,
operation: true
},
{
equipmentName: '重瓦斯保护',
equipmentState: 0,
currentState: 2,
operation: null
},
{
equipmentName: '压力缩放',
equipmentState: 0,
currentState: 2,
operation: null
},
{
equipmentName: '高压侧断路器',
equipmentState: 0,
currentState: 3,
operation: null
},
{
equipmentName: '中压侧断路器',
equipmentState: 0,
currentState: 3,
operation: null
},
{
equipmentName: '低压侧断路器',
equipmentState: 0,
currentState: 3,
operation: null
},
{
equipmentName: '断流阀',
equipmentState: 0,
currentState: 4,
operation: null
},
{
equipmentName: '排油阀',
equipmentState: 0,
currentState: 5,
operation: null
},
{
equipmentName: '注氮阀',
equipmentState: 0,
currentState: 5,
operation: null
},
{
equipmentName: '氮气瓶压力',
equipmentState: 0,
currentState: 7,
operation: null
},
{
equipmentName: '装置电源',
equipmentState: 0,
currentState: 6,
operation: null
}
];
interface SpanMethodProps {
row: any;
column: TableColumnCtx<User>;
rowIndex: number;
columnIndex: number;
}
//
const tableData = computed(() => {
return floorData.flatMap((floor) =>
floor.equipments.map((equipment) => ({
...equipment,
floorName: floor.floorName, //
//
address: equipment.address || floor.floorName
}))
);
});
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -1,5 +1,8 @@
<template> <template>
<el-row :gutter="20" style="display: flex; align-items: center"> <el-card
style="max-width: 100%; height: 100%; display: flex; flex-direction: column; overflow: hidden"
>
<el-row :gutter="20" style="flex-shrink: 0">
<el-col :span="24" class="centered-col"> <el-col :span="24" class="centered-col">
<el-text class="mx-1" size="large" style="font-size: 16px; margin-bottom: 15px" <el-text class="mx-1" size="large" style="font-size: 16px; margin-bottom: 15px"
>配置说明</el-text >配置说明</el-text
@ -7,12 +10,13 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20" style="flex: 1; overflow: hidden">
<el-col :span="24" class="centered-col"> <el-col :span="24" style="height: 100%">
<el-scrollbar>
<el-table <el-table
:data="tableData" :data="tableData"
:header-cell-style="{ color: '#3b3b3b ' }" :header-cell-style="{ color: '#3b3b3b ' }"
:style="{ height: '200px' }" :scrollbar-always-on="true"
> >
<!-- 序号 --> <!-- 序号 -->
<el-table-column <el-table-column
@ -51,8 +55,10 @@
align="left" align="left"
/> />
</el-table> </el-table>
</el-scrollbar>
</el-col> </el-col>
</el-row> </el-row>
</el-card>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, watch, onMounted, computed } from 'vue'; import { ref, reactive, watch, onMounted, computed } from 'vue';
@ -167,4 +173,12 @@ let computedSize = computed({
justify-content: center; /* 水平居中 */ justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */ align-items: center; /* 垂直居中 */
} }
/* 确保滚动条只在 el-scrollbar 中显示 */
:deep(.el-card__body) {
overflow: hidden;
height: 100%;
display: flex;
flex-direction: column;
}
</style> </style>

@ -3,6 +3,7 @@
<h2 class="cardHead">基本信息</h2> <h2 class="cardHead">基本信息</h2>
<div class="cardBody"> <div class="cardBody">
<el-scrollbar>
<el-row :gutter="0" style="display: flex; align-items: center"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="8" :offset="4"> 名称 </el-col> <el-col :span="8" :offset="4"> 名称 </el-col>
<el-col :span="4"> <el-col :span="4">
@ -86,6 +87,7 @@
<el-tag type="primary">188*****00 </el-tag> <el-tag type="primary">188*****00 </el-tag>
</el-col> </el-col>
</el-row> </el-row>
</el-scrollbar>
</div> </div>
</el-card> </el-card>
@ -304,8 +306,9 @@ P:hover {
} }
.cardBody { .cardBody {
width: 100%; width: 100%;
margin: 0 0%; margin: 0;
padding: 0px 0%; padding: 0;
/* padding-bottom: 15px; */ height: calc(100% - 40px); /* 减去标题高度 */
overflow: hidden;
} }
</style> </style>

@ -0,0 +1,143 @@
<template>
<el-card class="card">
<h3 class="cardHead">2号主变排油注氮灭火</h3>
<div class="cardBody">
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">火灾探测器1</el-tag>
</el-col>
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">火灾探测器2</el-tag>
</el-col>
</el-row>
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
<el-col :span="12" class="full-width-col">
<el-tag type="warning" size="large" class="full-width-tag">火灾探测器3</el-tag>
</el-col>
<el-col :span="12" class="full-width-col">
<el-tag type="primary" size="large" class="full-width-tag">火灾探测器4</el-tag>
</el-col>
</el-row>
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">注氮阀</el-tag>
</el-col>
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">排油阀</el-tag>
</el-col>
</el-row>
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">断流阀</el-tag>
</el-col>
<el-col :span="12" class="full-width-col">
<el-tag type="primary" size="large" class="full-width-tag">氮气瓶</el-tag>
</el-col>
</el-row>
</div>
</el-card>
</template>
<script lang="ts" setup>
import { computed, ref, watch, onMounted } from 'vue';
const props = defineProps({
fontFamily: {
type: String,
default: 'Segoe UI'
},
fontSize: {
type: Number,
default: 14
},
testColor: {
type: String,
default: '#000000'
},
testBool: {
type: Boolean,
default: true
}
});
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {
console.log('有人修改了fullName', val);
}
});
</script>
<style scoped>
.row-spacing {
margin-bottom: 10px; /* 每行之间的间隔 */
}
.full-width-col {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
.full-width-tag {
width: 85%; /* 填满父容器 */
text-align: center; /* 文字水平居中 */
display: flex; /* 使用 flexbox */
justify-content: center; /* 文字水平居中 */
align-items: center; /* 文字垂直居中 */
font-size: v-bind('computedSize');
}
/* 闪烁动画 */
.blinking-tag {
animation: blink 1s infinite; /* 1秒一次无限循环 */
}
@keyframes blink {
0%,
100% {
opacity: 1; /* 完全不透明 */
}
50% {
opacity: 0.3; /* 半透明 */
}
}
.card {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
/* max-width: 480px; */
color: v-bind('props.testColor');
font-family: v-bind('props.fontFamily');
/* font-family: 'Segoe UI'; */
font-size: v-bind('computedSize' - 1);
}
.cardHead {
margin: 0;
padding: 0px;
padding-bottom: 20px;
text-align: center;
color: #ffffff;
font-size: v-bind('computedSize' + 2);
}
.cardBody {
width: 100%;
margin: 0 0%;
padding: 0px 0%;
/* padding-bottom: 15px; */
}
</style>

@ -1,5 +1,6 @@
<template> <template>
<el-card class="card"> <el-card class="card">
<el-scrollbar height="100%">
<h2 class="cardHead">运行信息</h2> <h2 class="cardHead">运行信息</h2>
<div class="cardBody" v-if="globalOverviewBool"> <div class="cardBody" v-if="globalOverviewBool">
@ -106,7 +107,9 @@
<div class="blue-circle greenBordered"></div> <div class="blue-circle greenBordered"></div>
</el-col> </el-col>
<el-col :span="7" :offset="1" style="display: flex; align-items: center"> <el-col :span="7" :offset="1" style="display: flex; align-items: center">
<el-text class="mx-1" type="primary" @click="dialogTableVisible = true">灭火动作</el-text> <el-text class="mx-1" type="primary" @click="dialogTableVisible = true"
>灭火动作</el-text
>
<!-- 带边框的蓝色圆 --> <!-- 带边框的蓝色圆 -->
<div class="blue-circle redBordered"></div> <div class="blue-circle redBordered"></div>
@ -145,6 +148,7 @@
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</el-scrollbar>
</el-card> </el-card>
<!-- :append-to-body="true" --> <!-- :append-to-body="true" -->
@ -368,8 +372,9 @@ P:hover {
} }
.cardBody { .cardBody {
width: 100%; width: 100%;
height: 100%;
margin: 0 0%; margin: 0 0%;
padding: 0px 0%;
/* padding-bottom: 15px; */ /* padding-bottom: 15px; */
} }
</style> </style>

@ -46,44 +46,6 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<!-- <div class="table-wrapper">
<el-table
:data="tableData"
border
:span-method="objectSpanMethod"
class="full-height-table"
style="width: 100%"
@cell-click="handleCellClick"
>
<el-table-column prop="floorName" label="楼层" />
<el-table-column prop="id" label="设备ID" />
<el-table-column prop="name" label="设备名称" />
<el-table-column label="设备状态">
<template #default="{ row }">
<el-tag :type="row.eState === 0 ? 'success' : 'warning'">
{{ row.eState === 0 ? '正常' : '故障' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template #default="{ row }">
<el-tag v-if="row.currentState === 0" type="success"></el-tag>
<el-tag v-else-if="row.currentState === 1" type="info">停止</el-tag>
<el-tag v-else type="error">报警</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" class="operation-btn" v-if="row.operation">
屏蔽
</el-button>
<el-button type="primary" class="operation-btn" v-else> </el-button>
</template>
</el-table-column>
</el-table>
</div> -->
</el-card> </el-card>
</div> </div>
</template> </template>

@ -776,7 +776,6 @@ loader.load('/models/groundFloor/ground_floor08.gltf', (gltf: any) => {
moveArr.push(child as any); moveArr.push(child as any);
} else if (child.name.includes('smokeDetecto')) { } else if (child.name.includes('smokeDetecto')) {
console.log('@@aaa:', bindingArr);
// //
let smokePosition = child.position; let smokePosition = child.position;

@ -210,7 +210,6 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireControl/transformer', path: '/fireControl/transformer',
name: 'fireControlTransformer', name: 'fireControlTransformer',
component: () => import('@/views/edit/index.vue'),
meta: { meta: {
title: '变压器排油注氮灭火项目', title: '变压器排油注氮灭火项目',
hidden: false, hidden: false,
@ -222,7 +221,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireControl/transformer/index', path: '/fireControl/transformer/index',
name: 'fireControlTransformerIndex', name: 'fireControlTransformerIndex',
component: () => import('@/views/edit/index.vue'), component: () => import('@/views/preview/fireControl/alarm/transformer/index.vue'),
meta: { meta: {
title: '变压器排油注氮灭火', title: '变压器排油注氮灭火',
hidden: true, hidden: true,
@ -234,7 +233,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/transformer/host', path: '/fireFighting/transformer/host',
name: 'fireFightingTransformerHost', name: 'fireFightingTransformerHost',
component: () => import('@/views/edit/index.vue'), component: () => import('@/views/preview/fireControl/alarm/transformer/host.vue'),
meta: { meta: {
title: '主机', title: '主机',
hidden: false, hidden: false,
@ -246,7 +245,8 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/transformer/floor', path: '/fireFighting/transformer/floor',
name: 'fireFightingTransformerFloor', name: 'fireFightingTransformerFloor',
component: () => import('@/views/edit/index.vue'), // // src\views\preview\fireControl\alarm\transformer\nitrogen.vue
component: () => import('@/views/preview/fireControl/alarm/transformer/nitrogen.vue'),
meta: { meta: {
title: '2 号主变排油注氮灭火', title: '2 号主变排油注氮灭火',
hidden: false, hidden: false,
@ -260,7 +260,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/fireCock', path: '/fireFighting/fireCock',
name: 'fireFightingFireCock', name: 'fireFightingFireCock',
component: () => import('@/views/edit/index.vue'), component: () => import('@/views/preview/fireControl/alarm/fireHydrant.vue'),
meta: { meta: {
title: '消火栓系统', title: '消火栓系统',
hidden: false, hidden: false,
@ -272,7 +272,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/configuration', path: '/fireFighting/configuration',
name: 'fireFightingConfiguration', name: 'fireFightingConfiguration',
component: () => import('@/views/edit/index.vue'), component: () => import('@/views/preview/fireControl/alarm/fireExtinguisher.vue'),
meta: { meta: {
title: '灭火器配置', title: '灭火器配置',
hidden: false, hidden: false,
@ -284,7 +284,8 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/indicate', path: '/fireFighting/indicate',
name: 'fireFightingIndicator', name: 'fireFightingIndicator',
component: () => import('@/views/edit/index.vue'), // F:\vue\workspace\maotu-webtopo\src\views\preview\fireControl\alarm\indicate.vue
component: () => import('@/views/preview/fireControl/alarm/indicate.vue'),
meta: { meta: {
title: '消防应急照明及疏散指示系统', title: '消防应急照明及疏散指示系统',
hidden: false, hidden: false,
@ -811,8 +812,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
} }
} }
] ]
} },
,
{ {
path: '/test', //F:\vue\workspace\maotu-webtopo\src\views\preview\systemInfo\index.vue path: '/test', //F:\vue\workspace\maotu-webtopo\src\views\preview\systemInfo\index.vue
name: 'test', name: 'test',

@ -76,6 +76,7 @@ if (typeof window !== 'undefined') {
// 获取所有节点 // 获取所有节点
async function getData() { async function getData() {
try { try {
debugger;
const response = await modelApi.node_nrt_get(); const response = await modelApi.node_nrt_get();
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);

@ -0,0 +1,201 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { genExportJson, useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { objectDeepClone, randomString } from '@/components/mt-edit/utils/index';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
import type { IDoneJson } from '@/components/mt-edit/store/types';
const route = useRoute();
console.log('参数:', route.query.screen);
let drawerVisible = ref(false);
let fileNames: Array<{ id: string; name: string }> = reactive([]);
let radio = ref('-1');
//
let randomString1 = randomString();
//
function fileRead() {
fetch('/dataModes/index.json')
.then((response) => response.json())
.then((data) => {
fileNames = Object.assign(data);
})
.catch((error) => {
console.error('获取JSON文件错误', error);
});
}
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
//
function extractValFromProps(props: any) {
const result: Record<string, any> = {};
for (const key in props) {
if (props[key] && typeof props[key] === 'object' && 'val' in props[key]) {
result[key] = props[key].val;
}
}
return result;
}
//
function loadModeData() {
console.log('文件', route.query.screen);
console.log('xx:', globalStore.group_ids.get(route.query.screen as string));
if (globalStore.group_ids.get(route.query.screen as string)) {
let json: Array<IDoneJson> = objectDeepClone(
globalStore.group_ids.get(route.query.screen as string) || []
);
console.log('json1', json);
let endJson = {
canvasCfg: globalStore.canvasCfg,
gridCfg: globalStore.gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
}
function initLoad() {
let canvasCfg = globalStore.canvasCfg;
let gridCfg = globalStore.gridCfg;
// let json = globalStore.done_json;
let json: Array<any> = objectDeepClone(globalStore.done_json);
globalStore.done_json.forEach((item) => {
const extractedProps = extractValFromProps(item.props);
json.forEach((obj) => {
if (obj.id === item.id) {
obj.props = extractedProps;
}
});
});
let endJson = {
canvasCfg: canvasCfg,
gridCfg: gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
// globalStore.group_ids.set(route.query.screen as string, processedImportDoneJson);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onUnmounted(() => {
console.log('view卸载完毕');
});
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
//
function loadModel() {
console.log('选中:', radio.value, radio);
if (!radio.value || radio.value == '-1') {
ElMessage.warning('请先选择一个模型文件');
}
fileNames.forEach((item) => {
if (item.id == radio.value) {
fetch(`/dataModes/${item.name}`)
.then((response) => response.json())
.then((data) => {
console.log('文件内容:', data);
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(data);
globalStore.canvasCfg = canvasCfg;
globalStore.gridCfg = gridCfg;
globalStore.setGlobalStoreDoneJson(importDoneJson);
initLoad();
})
.catch((error) => {
ElMessage.error('获取文件错误:', error);
});
}
});
}
function test2() {
console.log('test3', globalStore);
}
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -0,0 +1,202 @@
<template>
<!-- <button @click="test2"></button> -->
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { genExportJson, useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { objectDeepClone, randomString } from '@/components/mt-edit/utils/index';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
import type { IDoneJson } from '@/components/mt-edit/store/types';
const route = useRoute();
console.log('参数:', route.query.screen);
let drawerVisible = ref(false);
let fileNames: Array<{ id: string; name: string }> = reactive([]);
let radio = ref('-1');
//
let randomString1 = randomString();
//
function fileRead() {
fetch('/dataModes/index.json')
.then((response) => response.json())
.then((data) => {
fileNames = Object.assign(data);
})
.catch((error) => {
console.error('获取JSON文件错误', error);
});
}
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
//
function extractValFromProps(props: any) {
const result: Record<string, any> = {};
for (const key in props) {
if (props[key] && typeof props[key] === 'object' && 'val' in props[key]) {
result[key] = props[key].val;
}
}
return result;
}
//
function loadModeData() {
console.log('文件', route.query.screen);
console.log('xx:', globalStore.group_ids.get(route.query.screen as string));
if (globalStore.group_ids.get(route.query.screen as string)) {
let json: Array<IDoneJson> = objectDeepClone(
globalStore.group_ids.get(route.query.screen as string) || []
);
console.log('json1', json);
let endJson = {
canvasCfg: globalStore.canvasCfg,
gridCfg: globalStore.gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
}
function initLoad() {
let canvasCfg = globalStore.canvasCfg;
let gridCfg = globalStore.gridCfg;
// let json = globalStore.done_json;
let json: Array<any> = objectDeepClone(globalStore.done_json);
globalStore.done_json.forEach((item) => {
const extractedProps = extractValFromProps(item.props);
json.forEach((obj) => {
if (obj.id === item.id) {
obj.props = extractedProps;
}
});
});
let endJson = {
canvasCfg: canvasCfg,
gridCfg: gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
// globalStore.group_ids.set(route.query.screen as string, processedImportDoneJson);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onUnmounted(() => {
console.log('view卸载完毕');
});
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
//
function loadModel() {
console.log('选中:', radio.value, radio);
if (!radio.value || radio.value == '-1') {
ElMessage.warning('请先选择一个模型文件');
}
fileNames.forEach((item) => {
if (item.id == radio.value) {
fetch(`/dataModes/${item.name}`)
.then((response) => response.json())
.then((data) => {
console.log('文件内容:', data);
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(data);
globalStore.canvasCfg = canvasCfg;
globalStore.gridCfg = gridCfg;
globalStore.setGlobalStoreDoneJson(importDoneJson);
initLoad();
})
.catch((error) => {
ElMessage.error('获取文件错误:', error);
});
}
});
}
function test2() {
console.log('test3', globalStore);
}
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -0,0 +1,168 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { genExportJson, useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { objectDeepClone, randomString } from '@/components/mt-edit/utils/index';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
import type { IDoneJson } from '@/components/mt-edit/store/types';
const route = useRoute();
console.log('参数:', route.query.screen);
let drawerVisible = ref(false);
let fileNames: Array<{ id: string; name: string }> = reactive([]);
let radio = ref('-1');
//
let randomString1 = randomString();
//
function fileRead() {
fetch('/dataModes/index.json')
.then((response) => response.json())
.then((data) => {
fileNames = Object.assign(data);
})
.catch((error) => {
console.error('获取JSON文件错误', error);
});
}
//
function loadModeData() {
console.log('文件', route.query.screen);
console.log('xx:', globalStore.group_ids.get(route.query.screen as string));
if (globalStore.group_ids.get(route.query.screen as string)) {
let json: Array<IDoneJson> = objectDeepClone(
globalStore.group_ids.get(route.query.screen as string) || ([] as IDoneJson[])
);
console.log('json1', json);
let endJson = {
canvasCfg: globalStore.canvasCfg,
gridCfg: globalStore.gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
}
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
//
function extractValFromProps(props: any) {
const result: Record<string, any> = {};
for (const key in props) {
if (props[key] && typeof props[key] === 'object' && 'val' in props[key]) {
result[key] = props[key].val;
}
}
return result;
}
function initLoad() {
let canvasCfg = globalStore.canvasCfg;
let gridCfg = globalStore.gridCfg;
// let json = globalStore.done_json;
let json: Array<any> = objectDeepClone(globalStore.done_json);
globalStore.done_json.forEach((item) => {
const extractedProps = extractValFromProps(item.props);
json.forEach((obj) => {
if (obj.id === item.id) {
obj.props = extractedProps;
}
});
});
let endJson = {
canvasCfg: canvasCfg,
gridCfg: gridCfg,
json: json
};
MtPreviewRef.value?.setImportJson(endJson);
}
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = await response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
// globalStore.group_ids.set(route.query.screen as string, processedImportDoneJson);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onUnmounted(() => {
console.log('view卸载完毕');
});
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -0,0 +1,91 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
const route = useRoute();
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
onUnmounted(() => {
console.log('view卸载完毕');
});
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = await response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
globalStore.group_ids.set(
route.query.screen as string,
processedImportDoneJson.map((item) => item.id)
);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -0,0 +1,91 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
const route = useRoute();
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
onUnmounted(() => {
console.log('view卸载完毕');
});
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = await response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
globalStore.group_ids.set(
route.query.screen as string,
processedImportDoneJson.map((item) => item.id)
);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -0,0 +1,93 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<!-- 2号主变 -->
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
const route = useRoute();
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
onUnmounted(() => {
console.log('view卸载完毕');
});
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = await response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
globalStore.group_ids.set(
route.query.screen as string,
processedImportDoneJson.map((item) => item.id)
);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>
Loading…
Cancel
Save