ソースを参照

1. 新增瓦斯抽采单元详情页面
2. 可配置页面echarts组件新增color设置
3. 潞安token登录接口数据进行处理

hongrunxia 2 ヶ月 前
コミット
6979daf432

+ 3 - 2
src/api/sys/user.ts

@@ -97,15 +97,16 @@ export function phoneLoginApi(params: LoginParams, mode: ErrorMessageMode = 'mod
   );
 }
 
-export function tokenLogin(params: TokenInfo, mode: ErrorMessageMode = 'modal') {
+export function tokenLogin(params: TokenInfo, mode: ErrorMessageMode = 'modal', successMode: SuccessMessageMode = 'success') {
   return defHttp.get<GetUserInfoModel>(
     {
       url: Api.tokenLogin,
       headers: {
-        Token: decodeURIComponent(params.token),
+        Token: params.token,
       },
     },
     {
+      successMessageMode: successMode,
       errorMessageMode: mode,
     }
   );

+ 2 - 2
src/components/vent/customHeader.vue

@@ -96,10 +96,10 @@
     --image-vent-header1: url('/@/assets/images/vent/vent-header1.png');
     --image-select-bg: url('/@/assets/images/vent/home/select-bg.png');
     width: 100%;
-    height: 30px;
+    position: relative;
+    z-index: 9999;
     .vent-home-header {
       width: 100%;
-
       position: fixed;
       top: 0;
       // background: url('/@/assets/images/vent/new-home/header-bg.png') no-repeat;

+ 4 - 3
src/hooks/vent/useAutoLogin.ts

@@ -76,9 +76,10 @@ export function useAutoLogin() {
   }
 
   async function doTokenLogin(token: string) {
-    await tokenLogin({ token });
-    userStore.setToken(token);
-    await userStore.getUserInfoAction();
+    tokenLogin({ token }).then(async () => {
+      await userStore.setToken(token);
+      await userStore.getUserInfoAction();
+    });
   }
 
   return {

+ 4 - 1
src/router/guard/permissionGuard.ts

@@ -69,7 +69,10 @@ export function createPermissionGuard(router: Router) {
       return next({ path: to.fullPath, replace: true, query: to.query });
     }
     if (tokenValidateRoute(to)) {
-      await doTokenLogin(to.query['token'] as string);
+      // url 地址的 token 数据没有进行encode, 使用searchParams 或 route.query会丢失个别字符
+      const url = new URL(window.location.href);
+      const tokenStr = url.search.split('?token=')[1];
+      await doTokenLogin(tokenStr);
     }
     // 如果指定了需要模拟登录则执行模拟登录,覆盖原有的登录信息
     if (to.query[MOCK_LOGIN_URL_QUERY.key] === MOCK_LOGIN_URL_QUERY.val) {

+ 1 - 0
src/utils/threejs/main.worker.ts

@@ -77,6 +77,7 @@ export function initModalWorker() {
     'workFace/workFace2-1_2024-04-09.glb',
     'workFace/workFace_2024-09-20.glb',
     'workFace/workFace1_2024-12-06.glb',
+    'gas/gasUnit_2024-12-18.glb',
   ];
 
   const db: any = new Dexie('DB');

+ 1 - 0
src/utils/threejs/useEvent.ts

@@ -48,6 +48,7 @@ export default function useEvent() {
   };
 
   const mouseUpFn = (modal, minDistance = 5, renderCallBack?) => {
+    debugger;
     const endTime = new Date().getTime();
     if (endTime - startTime > 400) {
       intersect0 = null;

+ 1 - 0
src/utils/threejs/util.ts

@@ -350,6 +350,7 @@ export const animateCamera = (oldP, oldT, newP, newT, model, duration = 0.5, cal
         ease: 'easeOutBounce',
         onUpdate: function (object) {
           // 这里写逻辑
+          debugger;
           camera.position.set(object.x1, object.y1, object.z1);
           controls.target.set(object.x2, object.y2, object.z2);
           controls.update();

+ 2 - 0
src/views/vent/deviceManager/configurationTable/types.ts

@@ -223,6 +223,8 @@ export interface ModuleDataChart extends ReadFrom {
     xprop: string;
     /** 取值 prop,注意该项不支持 formatter 格式,将用于 yAxis 相关的内容 */
     yprop: string;
+
+    color?: string;
   }[];
   /** 图表legend配置 */
   legend: {

+ 280 - 0
src/views/vent/gas/gasAssessment/components/gasUnit.vue

@@ -0,0 +1,280 @@
+<template>
+  <CustomBadges class="w-1710px ml-100px mt-50px" :badges="unitHeaderBadges" />
+  <div class="monitor-container">
+    <div class="lr left-box">
+      <ventBox1>
+        <template #title>
+          <div>评价单元基础信息</div>
+        </template>
+        <template #container>
+          <ListItem
+            v-for="(item, index) in gasUnitBase"
+            :key="index"
+            class="w-100% mb-5px"
+            :value="get(dataSource, item.code)"
+            :label="item.title"
+            labelWidth="200px"
+          />
+        </template>
+      </ventBox1>
+
+      <ventBox1 class="vent-margin-t-10">
+        <template #title>
+          <div>单元累计抽采混量</div>
+        </template>
+        <template #container>
+          <CustomChart :chart-config="gasUnitHlOption" :chart-data="mockGasUnitHlData" height="280px" />
+        </template>
+      </ventBox1>
+    </div>
+    <div class="lr right-box">
+      <div class="item-box">
+        <ventBox1>
+          <template #title>
+            <div>实时监测数据</div>
+          </template>
+          <template #container>
+            <ListItem
+              v-for="(item, index) in gasUnitMonitor"
+              :key="index"
+              class="w-100% mb-5px"
+              :value="get(dataSource, item.code)"
+              :label="item.title"
+              labelWidth="200px"
+            />
+          </template>
+        </ventBox1>
+        <ventBox1 class="vent-margin-t-10">
+          <template #title>
+            <div>单元累计抽采纯量</div>
+          </template>
+          <template #container>
+            <CustomChart :chart-config="gasUnitClOption" :chart-data="mockGasUnitClData" height="280px" />
+          </template>
+        </ventBox1>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { onBeforeMount, ref, onMounted, onUnmounted } from 'vue';
+  import ventBox1 from '/@/components/vent/ventBox1.vue';
+  import CustomBadges from './customHeader.vue';
+  import {
+    gasUnitMonitor,
+    unitHeaderBadges,
+    gasUnitBase,
+    gasUnitHlOption,
+    mockGasUnitHlData,
+    gasUnitClOption,
+    mockGasUnitClData,
+  } from '../gasAssessment.data';
+  import ListItem from '@/views/vent/gas/components/list/listItem.vue';
+  import { get } from '@/utils/ventutil';
+  import CustomChart from '@/views/vent/home/configurable/components/detail/CustomChart.vue';
+  import { list } from '../gasAssessment.api';
+
+  let props = withDefaults(
+    defineProps<{
+      unitId: string;
+    }>(),
+    {
+      unitId: '',
+    }
+  );
+  const loading = ref(false);
+  const dataSource = ref({});
+
+  // // https获取监测数据
+  let timer: null | NodeJS.Timeout = null;
+  function getMonitor(flag?) {
+    if (Object.prototype.toString.call(timer) === '[object Null]') {
+      timer = setTimeout(
+        async () => {
+          const res = await list({ ids: props.unitId, pagetype: 'normal' });
+          if (res.msgTxt && res.msgTxt[0]) {
+            const data = res.msgTxt[0].datalist[0] || [];
+            dataSource.value = Object.assign(data, data['readData']);
+            if (timer) {
+              timer = null;
+            }
+            getMonitor();
+          }
+          if (timer) {
+            timer = null;
+          }
+          await getMonitor();
+          loading.value = false;
+        },
+        flag ? 0 : 1000
+      );
+    }
+  }
+
+  onBeforeMount(() => {});
+
+  onMounted(async () => {
+    getMonitor(true);
+    loading.value = false;
+  });
+
+  onUnmounted(() => {
+    if (timer) {
+      clearTimeout(timer);
+    }
+  });
+</script>
+
+<style lang="less">
+  @import '/@/design/vent/modal.less';
+
+  .@{ventSpace}-select-dropdown {
+    background: #ffffff !important;
+    border-bottom: 1px solid rgba(236, 236, 236, 0.4);
+    backdrop-filter: blur(10px);
+
+    .@{ventSpace}-select-item-option-selected,
+    .@{ventSpace}-select-item-option-active {
+      background-color: #ffffff33 !important;
+    }
+
+    .@{ventSpace}-select-item:hover {
+      background-color: #ffffff33 !important;
+    }
+  }
+</style>
+
+<style lang="less" scoped>
+  @ventSpace: zxm;
+  @import '/@/design/vent/modal.less';
+  @import '@/views/vent/monitorManager/comment/less/workFace.less';
+  .bg {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    overflow: hidden;
+    position: absolute;
+    pointer-events: auto;
+    z-index: 0;
+  }
+  .monitor-container {
+    height: 850px;
+    pointer-events: none;
+  }
+  .modal-monitor {
+    position: absolute;
+    z-index: -1;
+    flex-direction: row-reverse;
+    .main-container {
+      background-color: #00000078;
+    }
+    .monitor-item {
+      width: 180px;
+      display: flex;
+      flex-direction: row;
+      width: auto;
+      margin-bottom: 3px;
+      .monitor-title {
+        width: 120px;
+        color: #7af5ff;
+        font-weight: 400;
+        font-size: 13px;
+      }
+      .monitor-val {
+        color: #ffb700;
+        display: flex;
+        width: auto;
+
+        .val {
+          width: 60px;
+          font-size: 13px;
+          text-align: center;
+        }
+
+        .unit {
+          color: #ffffffbb;
+          font-size: 13px;
+        }
+      }
+    }
+    .title {
+      text-align: center;
+    }
+  }
+  .left-box {
+    width: 360px;
+  }
+  .gas-pump-item {
+    padding: 3px 0;
+  }
+
+  .param-set {
+    color: #45d3fd;
+    cursor: pointer;
+    &:hover {
+      color: #38a6c8;
+    }
+  }
+
+  .input-item {
+    margin: 3px 0 !important;
+    .value {
+      width: 80px;
+      text-align: center;
+    }
+  }
+  .data-group {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-between;
+    padding-bottom: 8px;
+    .data-item {
+      width: calc(50% - 10px);
+      display: flex;
+      justify-content: space-between;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
+      margin: 4px 0;
+    }
+    .value {
+      color: #00eefffe;
+    }
+    .data-item1 {
+      width: 100%;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
+      margin: 4px 0;
+    }
+  }
+
+  .base-title {
+    line-height: 26px;
+    position: relative;
+    padding-left: 15px;
+    color: #9bf2ff;
+    &::after {
+      content: '';
+      position: absolute;
+      display: block;
+      width: 4px;
+      height: 12px;
+      top: 8px;
+      left: 5px;
+      background: #45d3fd;
+      border-radius: 4px;
+    }
+  }
+
+  .detail {
+    border: 1px solid #9bf2ff88;
+    padding: 0 5px;
+    background-color: #ffffff11;
+    margin-right: 4px;
+    &:hover {
+      background-color: #ffffff05;
+    }
+  }
+</style>

+ 216 - 0
src/views/vent/gas/gasAssessment/components/workFace.vue

@@ -0,0 +1,216 @@
+<template>
+  <CustomBadges class="w-1710px ml-100px mt-50px" :badges="headerBadges" />
+  <div class="monitor-container">
+    <div class="lr left-box">
+      <ventBox1>
+        <template #title>
+          <div>工作面基础信息</div>
+        </template>
+        <template #container>
+          <ListItem
+            v-for="(item, index) in gasMonitor"
+            :key="index"
+            class="w-100% mb-5px"
+            :value="get(dataSource, item.code)"
+            :label="item.title"
+            labelWidth="200px"
+          />
+        </template>
+      </ventBox1>
+
+      <ventBox1 class="vent-margin-t-10">
+        <template #title>
+          <div>工作面基础信息</div>
+        </template>
+        <template #container>
+          <CustomChart :chart-config="gasUnitBarOption" :chart-data="mockData" height="280px" />
+        </template>
+      </ventBox1>
+    </div>
+    <div class="lr right-box">
+      <div class="item-box">
+        <ventBox1>
+          <template #title>
+            <div>工作面支管抽采信息</div>
+          </template>
+          <template #container>
+            <ListItem
+              v-for="(item, index) in gasPumpValve"
+              :key="index"
+              class="w-100% mb-5px"
+              :value="get(dataSource, item.code)"
+              :label="item.title"
+              labelWidth="200px"
+            />
+          </template>
+        </ventBox1>
+        <ventBox1 class="vent-margin-t-10">
+          <template #title>
+            <div>工作面基础信息</div>
+          </template>
+          <template #container>
+            <CustomChart :chart-config="gasUnitPieOption" :chart-data="mockPieData" height="280px" />
+          </template>
+        </ventBox1>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ref, onMounted } from 'vue';
+  import ventBox1 from '/@/components/vent/ventBox1.vue';
+  import CustomBadges from './customHeader.vue';
+  import { gasMonitor, headerBadges, gasPumpValve, gasUnitBarOption, mockData, gasUnitPieOption, mockPieData } from '../gasAssessment.data';
+  import ListItem from '@/views/vent/gas/components/list/listItem.vue';
+  import { get } from '@/utils/ventutil';
+  import CustomChart from '@/views/vent/home/configurable/components/detail/CustomChart.vue';
+
+  const loading = ref(false);
+  const dataSource = ref({});
+
+  // // https获取监测数据
+  let timer: null | NodeJS.Timeout = null;
+  function getMonitor(flag?) {
+    if (Object.prototype.toString.call(timer) === '[object Null]') {
+      timer = setTimeout(
+        async () => {
+          if (timer) {
+            timer = null;
+          }
+          await getMonitor();
+          loading.value = false;
+        },
+        flag ? 0 : 1000
+      );
+    }
+  }
+
+  onMounted(async () => {
+    timer = null;
+    getMonitor(true);
+  });
+</script>
+
+<style lang="less" scoped>
+  @ventSpace: zxm;
+  @import '/@/design/vent/modal.less';
+  @import '@/views/vent/monitorManager/comment/less/workFace.less';
+  .monitor-container {
+    height: 850px;
+    pointer-events: none;
+  }
+  .modal-monitor {
+    position: absolute;
+    z-index: -1;
+    flex-direction: row-reverse;
+    .main-container {
+      background-color: #00000078;
+    }
+    .monitor-item {
+      width: 180px;
+      display: flex;
+      flex-direction: row;
+      width: auto;
+      margin-bottom: 3px;
+      .monitor-title {
+        width: 120px;
+        color: #7af5ff;
+        font-weight: 400;
+        font-size: 13px;
+      }
+      .monitor-val {
+        color: #ffb700;
+        display: flex;
+        width: auto;
+
+        .val {
+          width: 60px;
+          font-size: 13px;
+          text-align: center;
+        }
+
+        .unit {
+          color: #ffffffbb;
+          font-size: 13px;
+        }
+      }
+    }
+    .title {
+      text-align: center;
+    }
+  }
+  .left-box {
+    width: 360px;
+  }
+  .gas-pump-item {
+    padding: 3px 0;
+  }
+
+  .param-set {
+    color: #45d3fd;
+    cursor: pointer;
+    &:hover {
+      color: #38a6c8;
+    }
+  }
+
+  .input-item {
+    margin: 3px 0 !important;
+    .value {
+      width: 80px;
+      text-align: center;
+    }
+  }
+  .data-group {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-between;
+    padding-bottom: 8px;
+    .data-item {
+      width: calc(50% - 10px);
+      display: flex;
+      justify-content: space-between;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
+      margin: 4px 0;
+    }
+    .value {
+      color: #00eefffe;
+    }
+    .data-item1 {
+      width: 100%;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
+      margin: 4px 0;
+    }
+  }
+
+  .base-title {
+    line-height: 26px;
+    position: relative;
+    padding-left: 15px;
+    color: #9bf2ff;
+    &::after {
+      content: '';
+      position: absolute;
+      display: block;
+      width: 4px;
+      height: 12px;
+      top: 8px;
+      left: 5px;
+      background: #45d3fd;
+      border-radius: 4px;
+    }
+  }
+
+  .detail {
+    border: 1px solid #9bf2ff88;
+    padding: 0 5px;
+    background-color: #ffffff11;
+    margin-right: 4px;
+    &:hover {
+      background-color: #ffffff05;
+    }
+  }
+</style>

+ 10 - 0
src/views/vent/gas/gasAssessment/gasAssessment.api.ts

@@ -0,0 +1,10 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  list = '/monitor/device',
+}
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.post({ url: Api.list, params });

+ 80 - 0
src/views/vent/gas/gasAssessment/gasAssessment.data.ts

@@ -552,6 +552,86 @@ export const mockPieData = {
   ],
 };
 
+export const gasUnitHlOption: ModuleDataChart = {
+  type: 'line_area',
+  readFrom: '',
+  legend: { show: false },
+  xAxis: [{ show: true }],
+  yAxis: [{ show: true, name: '混量(m³/t)', position: 'left' }],
+  series: [{ readFrom: 'history', xprop: 'time', yprop: 'val', label: '单元瓦斯混量' }],
+};
+
+export const mockGasUnitHlData = {
+  id: 4,
+  objType: '氧气',
+  history: [
+    {
+      time: '2024-12-13',
+      val: '113.76',
+    },
+    {
+      time: '2024-12-14',
+      val: '153.76',
+    },
+    {
+      time: '2024-12-15',
+      val: '163.76',
+    },
+    {
+      time: '2024-12-16',
+      val: '193.76',
+    },
+    {
+      time: '2024-12-17',
+      val: '203.76',
+    },
+    {
+      time: '2024-12-18',
+      val: '223.76',
+    },
+  ],
+};
+
+export const gasUnitClOption: ModuleDataChart = {
+  type: 'line_area',
+  readFrom: '',
+  legend: { show: false },
+  xAxis: [{ show: true }],
+  yAxis: [{ show: true, name: '纯量(m³/t)', position: 'left' }],
+  series: [{ readFrom: 'history', xprop: 'time', yprop: 'val', label: '单元瓦斯纯量', color: '#FAC858' }],
+};
+
+export const mockGasUnitClData = {
+  id: 4,
+  objType: '氧气',
+  history: [
+    {
+      time: '2024-12-13',
+      val: '103.76',
+    },
+    {
+      time: '2024-12-14',
+      val: '133.76',
+    },
+    {
+      time: '2024-12-15',
+      val: '143.76',
+    },
+    {
+      time: '2024-12-16',
+      val: '173.76',
+    },
+    {
+      time: '2024-12-17',
+      val: '193.76',
+    },
+    {
+      time: '2024-12-18',
+      val: '213.76',
+    },
+  ],
+};
+
 export const unitHeaderBadges = ref([
   {
     value: 'T1',

+ 0 - 350
src/views/vent/gas/gasAssessment/gasUnit.vue

@@ -1,350 +0,0 @@
-<template>
-  <CustomHeader>瓦斯抽采达标评判</CustomHeader>
-  <CustomBadges class="w-1710px ml-100px mt-50px" :badges="unitHeaderBadges" />
-  <a-spin tip="Loading..." :spinning="loading">
-    <div class="bg" style="">
-      <div id="workFace3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden; z-index: 1; top: 0"> </div>
-      <div
-        id="workFace3DCSS"
-        class="threejs-Object-CSS"
-        style="width: 100%; height: 100%; position: absolute; pointer-events: none; overflow: hidden; z-index: 1; top: 0"
-      >
-      </div>
-    </div>
-
-    <div class="modal-monitor vent-flex-row" style="display: none">
-      <div v-for="groupNum in monitorDataGroupNum" :id="'gasUnitBox' + groupNum" :key="groupNum" style="margin: 0 5px">
-        <FourBorderBg class="four-border-bg">
-          <div class="title">抽采单元{{ groupNum }}</div>
-          <div class="monitor-item" v-for="(gasUnit, index) in gasUnitDetail" :key="index">
-            <span class="monitor-title">{{ gasUnit.title }}:</span>
-            <span class="monitor-val">
-              <span class="val">
-                {{ selectData[groupNum - 1] && selectData[groupNum - 1][gasUnit.code] ? selectData[groupNum - 1][gasUnit.code] : '-' }}
-              </span>
-            </span>
-          </div>
-        </FourBorderBg>
-      </div>
-    </div>
-    <div class="monitor-container">
-      <div class="lr left-box">
-        <ventBox1>
-          <template #title>
-            <div>评价单元基础信息</div>
-          </template>
-          <template #container>
-            <ListItem
-              v-for="(item, index) in gasUnitBase"
-              :key="index"
-              class="w-100% mb-5px"
-              :value="get(dataSource, item.code)"
-              :label="item.title"
-              labelWidth="200px"
-            />
-          </template>
-        </ventBox1>
-
-        <ventBox1 class="vent-margin-t-10">
-          <template #title>
-            <div>单元累计抽采混量</div>
-          </template>
-          <template #container>
-            <CustomChart :chart-config="gasUnitBarOption" :chart-data="mockData" height="280px" />
-          </template>
-        </ventBox1>
-      </div>
-      <div class="lr right-box">
-        <div class="item-box">
-          <ventBox1>
-            <template #title>
-              <div>实时监测数据</div>
-            </template>
-            <template #container>
-              <ListItem
-                v-for="(item, index) in gasUnitMonitor"
-                :key="index"
-                class="w-100% mb-5px"
-                :value="get(dataSource, item.code)"
-                :label="item.title"
-                labelWidth="200px"
-              />
-            </template>
-          </ventBox1>
-          <ventBox1 class="vent-margin-t-10">
-            <template #title>
-              <div>工作面基础信息</div>
-            </template>
-            <template #container>
-              <CustomChart :chart-config="gasUnitPieOption" :chart-data="mockPieData" height="280px" />
-            </template>
-          </ventBox1>
-        </div>
-      </div>
-    </div>
-  </a-spin>
-</template>
-
-<script setup lang="ts">
-  import FourBorderBg from '/@/components/vent/fourBorderBg.vue';
-  import { onBeforeMount, ref, onMounted, onUnmounted, nextTick, unref, computed } from 'vue';
-  import ventBox1 from '/@/components/vent/ventBox1.vue';
-  import CustomHeader from '/@/components/vent/customHeader.vue';
-  import CustomBadges from './components/customHeader.vue';
-  import {
-    gasUnitMonitor,
-    gasUnitDetail,
-    unitHeaderBadges,
-    gasUnitBase,
-    gasUnitBarOption,
-    mockData,
-    gasUnitPieOption,
-    mockPieData,
-  } from './gasAssessment.data';
-  import { mountedThree, destroy, setModelType, setCss3D } from './threejs/gasAssessmen.threejs';
-  import { useSystemSelect } from '/@/hooks/vent/useSystemSelect';
-  import ListItem from '@/views/vent/gas/components/list/listItem.vue';
-  import { get } from '@/utils/ventutil';
-  import CustomChart from '@/views/vent/home/configurable/components/detail/CustomChart.vue';
-  import { useRouter } from 'vue-router';
-
-  const { currentRoute } = useRouter();
-  const loading = ref(false);
-  const dataSource = ref({});
-  const unitId = ref('');
-  // 获取模型类型
-  const changeModalType = (currentData) => {
-    if (currentData) {
-      if (currentData['strsystype'] === 'sys_surface_caimei_modal_1') {
-        // 单进单回
-        modalType = 'workFace1';
-      } else if (currentData['strsystype'] === 'sys_surface_caimei_modal_3') {
-        // 双进单回
-        modalType = 'workFace3';
-      } else if (currentData['strsystype'] === 'sys_surface_caimei_modal_4') {
-        // 双进双回
-        modalType = 'workFace4';
-      } else {
-        modalType = 'workFace3';
-      }
-    } else {
-      modalType = 'workFace3';
-    }
-
-    gasUnitNum.value = 4;
-    setModelType(modalType, gasUnitNum.value, true);
-  };
-
-  const { options, optionValue, deviceActive, getSelectRow, getSysDataSource, getDeviceList } = useSystemSelect(
-    'sys_surface_caimei',
-    changeModalType
-  );
-
-  const gasUnitNum = ref(5);
-  let modalType = 'workFace1';
-
-  // // 监测数据
-  const selectData = ref([]);
-  const monitorDataGroupNum = ref(5);
-  // // https获取监测数据
-  let timer: null | NodeJS.Timeout = null;
-  function getMonitor(flag?) {
-    if (Object.prototype.toString.call(timer) === '[object Null]') {
-      timer = setTimeout(
-        async () => {
-          if (deviceActive.value) {
-            await getDeviceList();
-          }
-          if (timer) {
-            timer = null;
-          }
-          await getMonitor();
-          loading.value = false;
-        },
-        flag ? 0 : 1000
-      );
-    }
-  }
-
-  onBeforeMount(() => {});
-
-  onMounted(async () => {
-    const { query } = unref(currentRoute);
-    if (query['deviceType']) unitId.value = query['id'] as string;
-    loading.value = true;
-    timer = null;
-    mountedThree().then(async () => {
-      // gasUnitNum.value = Math.ceil(Math.random() * 10)
-      gasUnitNum.value = 4;
-      loading.value = false;
-      // nextTick(() => {
-      //   setModelType(modalType, gasUnitNum.value, true);
-      // });
-      await getSysDataSource();
-      nextTick(async () => {
-        await getMonitor(true);
-        setCss3D();
-      });
-    });
-  });
-  onUnmounted(() => {
-    if (timer) {
-      clearTimeout(timer);
-      timer = undefined;
-    }
-    destroy();
-  });
-</script>
-
-<style lang="less">
-  @import '/@/design/vent/modal.less';
-
-  .@{ventSpace}-select-dropdown {
-    background: #ffffff !important;
-    border-bottom: 1px solid rgba(236, 236, 236, 0.4);
-    backdrop-filter: blur(10px);
-
-    .@{ventSpace}-select-item-option-selected,
-    .@{ventSpace}-select-item-option-active {
-      background-color: #ffffff33 !important;
-    }
-
-    .@{ventSpace}-select-item:hover {
-      background-color: #ffffff33 !important;
-    }
-  }
-</style>
-
-<style lang="less" scoped>
-  @ventSpace: zxm;
-  @import '/@/design/vent/modal.less';
-  @import '@/views/vent/monitorManager/comment/less/workFace.less';
-  .bg {
-    width: 100%;
-    height: 100%;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    overflow: hidden;
-    position: absolute;
-    pointer-events: auto;
-    z-index: 0;
-  }
-  :deep(.monitor-container) {
-    height: 850px;
-    pointer-events: none;
-  }
-  .modal-monitor {
-    position: absolute;
-    z-index: -1;
-    flex-direction: row-reverse;
-    :deep(.main-container) {
-      background-color: #00000078;
-    }
-    .monitor-item {
-      width: 180px;
-      display: flex;
-      flex-direction: row;
-      width: auto;
-      margin-bottom: 3px;
-      .monitor-title {
-        width: 120px;
-        color: #7af5ff;
-        font-weight: 400;
-        font-size: 13px;
-      }
-      .monitor-val {
-        color: #ffb700;
-        display: flex;
-        width: auto;
-
-        .val {
-          width: 60px;
-          font-size: 13px;
-          text-align: center;
-        }
-
-        .unit {
-          color: #ffffffbb;
-          font-size: 13px;
-        }
-      }
-    }
-    .title {
-      text-align: center;
-    }
-  }
-  .left-box {
-    width: 360px;
-  }
-  .gas-pump-item {
-    padding: 3px 0;
-  }
-
-  .param-set {
-    color: #45d3fd;
-    cursor: pointer;
-    &:hover {
-      color: #38a6c8;
-    }
-  }
-
-  .input-item {
-    margin: 3px 0 !important;
-    .value {
-      width: 80px;
-      text-align: center;
-    }
-  }
-  .data-group {
-    display: flex;
-    flex-wrap: wrap;
-    justify-content: space-between;
-    padding-bottom: 8px;
-    .data-item {
-      width: calc(50% - 10px);
-      display: flex;
-      justify-content: space-between;
-      line-height: 24px;
-      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
-      margin: 4px 0;
-    }
-    .value {
-      color: #00eefffe;
-    }
-    .data-item1 {
-      width: 100%;
-      line-height: 24px;
-      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
-      margin: 4px 0;
-    }
-  }
-
-  .base-title {
-    line-height: 26px;
-    position: relative;
-    padding-left: 15px;
-    color: #9bf2ff;
-    &::after {
-      content: '';
-      position: absolute;
-      display: block;
-      width: 4px;
-      height: 12px;
-      top: 8px;
-      left: 5px;
-      background: #45d3fd;
-      border-radius: 4px;
-    }
-  }
-
-  .detail {
-    border: 1px solid #9bf2ff88;
-    padding: 0 5px;
-    background-color: #ffffff11;
-    margin-right: 4px;
-    &:hover {
-      background-color: #ffffff05;
-    }
-  }
-</style>

+ 44 - 233
src/views/vent/gas/gasAssessment/index.vue

@@ -6,136 +6,53 @@
     :optionValue="optionValue"
     >瓦斯抽采达标评判</CustomHeader
   >
-  <CustomBadges class="w-1710px ml-100px mt-50px" :badges="headerBadges" />
-  <a-spin tip="Loading..." :spinning="loading">
-    <div class="bg" style="">
-      <div id="workFace3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden; z-index: 1; top: 0"> </div>
-      <div
-        id="workFace3DCSS"
-        class="threejs-Object-CSS"
-        style="width: 100%; height: 100%; position: absolute; pointer-events: none; overflow: hidden; z-index: 1; top: 0"
-      >
-      </div>
+  <div class="bg" style="">
+    <div id="workFace3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden; z-index: 1; top: 0; pointer-events: auto"> </div>
+    <div
+      id="workFace3DCSS"
+      v-show="pageType == 'workFace'"
+      class="threejs-Object-CSS"
+      style="width: 100%; height: 100%; position: absolute; pointer-events: none; overflow: hidden; z-index: 1; top: 0"
+    >
     </div>
-
-    <div class="modal-monitor vent-flex-row" style="display: none">
-      <div v-for="groupNum in monitorDataGroupNum" :id="'gasUnitBox' + groupNum" :key="groupNum" style="margin: 0 5px">
-        <FourBorderBg class="four-border-bg">
-          <div class="title">抽采单元{{ groupNum }}</div>
-          <div class="monitor-item" v-for="(gasUnit, index) in gasUnitDetail" :key="index">
-            <span class="monitor-title">{{ gasUnit.title }}:</span>
-            <span class="monitor-val">
-              <span class="val">
-                {{ selectData[groupNum - 1] && selectData[groupNum - 1][gasUnit.code] ? selectData[groupNum - 1][gasUnit.code] : '-' }}
-              </span>
+  </div>
+  <div class="modal-monitor vent-flex-row" style="display: none">
+    <div v-for="groupNum in monitorDataGroupNum" :id="'gasUnitBox' + groupNum" :key="groupNum" style="margin: 0 5px">
+      <FourBorderBg class="four-border-bg">
+        <div class="title">抽采单元{{ groupNum }}</div>
+        <div class="monitor-item" v-for="(gasUnit, index) in gasUnitDetail" :key="index">
+          <span class="monitor-title">{{ gasUnit.title }}:</span>
+          <span class="monitor-val">
+            <span class="val">
+              {{ selectData[groupNum - 1] && selectData[groupNum - 1][gasUnit.code] ? selectData[groupNum - 1][gasUnit.code] : '-' }}
             </span>
-          </div>
-        </FourBorderBg>
-      </div>
-    </div>
-    <div class="monitor-container">
-      <div class="lr left-box">
-        <ventBox1>
-          <template #title>
-            <div>工作面基础信息</div>
-          </template>
-          <template #container>
-            <ListItem
-              v-for="(item, index) in gasMonitor"
-              :key="index"
-              class="w-100% mb-5px"
-              :value="get(dataSource, item.code)"
-              :label="item.title"
-              labelWidth="200px"
-            />
-          </template>
-        </ventBox1>
-
-        <ventBox1 class="vent-margin-t-10">
-          <template #title>
-            <div>工作面基础信息</div>
-          </template>
-          <template #container>
-            <CustomChart :chart-config="gasUnitBarOption" :chart-data="mockData" height="280px" />
-          </template>
-        </ventBox1>
-      </div>
-      <div class="lr right-box">
-        <div class="item-box">
-          <ventBox1>
-            <template #title>
-              <div>工作面支管抽采信息</div>
-            </template>
-            <template #container>
-              <ListItem
-                v-for="(item, index) in gasPumpValve"
-                :key="index"
-                class="w-100% mb-5px"
-                :value="get(dataSource, item.code)"
-                :label="item.title"
-                labelWidth="200px"
-              />
-            </template>
-          </ventBox1>
-          <ventBox1 class="vent-margin-t-10">
-            <template #title>
-              <div>工作面基础信息</div>
-            </template>
-            <template #container>
-              <CustomChart :chart-config="gasUnitPieOption" :chart-data="mockPieData" height="280px" />
-            </template>
-          </ventBox1>
+          </span>
         </div>
-      </div>
+      </FourBorderBg>
     </div>
-  </a-spin>
+  </div>
+  <WorkFace class="point-event" v-if="pageType == 'workFace'" />
+  <gasUnit class="point-event" v-if="pageType == 'gasUnit'" />
 </template>
 
 <script setup lang="ts">
   import FourBorderBg from '/@/components/vent/fourBorderBg.vue';
-  import { onBeforeMount, ref, onMounted, onUnmounted, nextTick, watch, computed } from 'vue';
-  import ventBox1 from '/@/components/vent/ventBox1.vue';
+  import { onBeforeMount, ref, onMounted, onUnmounted, nextTick, watch } from 'vue';
   import CustomHeader from '/@/components/vent/customHeader.vue';
-  import CustomBadges from './components/customHeader.vue';
-  import {
-    gasMonitor,
-    gasUnitDetail,
-    headerBadges,
-    gasPumpValve,
-    gasUnitBarOption,
-    mockData,
-    gasUnitPieOption,
-    mockPieData,
-  } from './gasAssessment.data';
+  import { gasUnitDetail } from './gasAssessment.data';
   import { mountedThree, destroy, setModelType, setCss3D } from './threejs/gasAssessmen.threejs';
   import { useSystemSelect } from '/@/hooks/vent/useSystemSelect';
-  import ListItem from '@/views/vent/gas/components/list/listItem.vue';
-  import { get } from '@/utils/ventutil';
-  import CustomChart from '@/views/vent/home/configurable/components/detail/CustomChart.vue';
+  import gasUnit from './components/gasUnit.vue';
+  import WorkFace from './components/workFace.vue';
 
   const loading = ref(false);
   const dataSource = ref({});
+  const pageType = ref('workFace');
+  const activeUnitId = ref('');
   // 获取模型类型
   const changeModalType = (currentData) => {
-    if (currentData) {
-      if (currentData['strsystype'] === 'sys_surface_caimei_modal_1') {
-        // 单进单回
-        modalType = 'workFace1';
-      } else if (currentData['strsystype'] === 'sys_surface_caimei_modal_3') {
-        // 双进单回
-        modalType = 'workFace3';
-      } else if (currentData['strsystype'] === 'sys_surface_caimei_modal_4') {
-        // 双进双回
-        modalType = 'workFace4';
-      } else {
-        modalType = 'workFace3';
-      }
-    } else {
-      modalType = 'workFace3';
-    }
-
     gasUnitNum.value = 4;
-    setModelType(modalType, gasUnitNum.value, true);
+    setModelType(modalType, gasUnitNum.value);
   };
 
   const { options, optionValue, deviceActive, getSelectRow, getSysDataSource, getDeviceList } = useSystemSelect(
@@ -169,6 +86,17 @@
     }
   }
 
+  watch(
+    pageType,
+    (newVal, oldVal) => {
+      console.log('页面类型', newVal);
+      if (newVal == 'gasUnit') {
+      } else if (newVal == 'workFace') {
+      }
+    },
+    {}
+  );
+
   onBeforeMount(() => {});
 
   onMounted(async () => {
@@ -176,13 +104,10 @@
 
     timer = null;
 
-    mountedThree().then(async () => {
+    mountedThree(pageType, activeUnitId).then(async () => {
       // gasUnitNum.value = Math.ceil(Math.random() * 10)
       gasUnitNum.value = 4;
       loading.value = false;
-      // nextTick(() => {
-      //   setModelType(modalType, gasUnitNum.value, true);
-      // });
       await getSysDataSource();
       nextTick(async () => {
         await getMonitor(true);
@@ -233,121 +158,7 @@
     pointer-events: auto;
     z-index: 0;
   }
-  :deep(.monitor-container) {
-    height: 850px;
-    pointer-events: none;
-  }
-  .modal-monitor {
-    position: absolute;
-    z-index: -1;
-    flex-direction: row-reverse;
-    :deep(.main-container) {
-      background-color: #00000078;
-    }
-    .monitor-item {
-      width: 180px;
-      display: flex;
-      flex-direction: row;
-      width: auto;
-      margin-bottom: 3px;
-      .monitor-title {
-        width: 120px;
-        color: #7af5ff;
-        font-weight: 400;
-        font-size: 13px;
-      }
-      .monitor-val {
-        color: #ffb700;
-        display: flex;
-        width: auto;
-
-        .val {
-          width: 60px;
-          font-size: 13px;
-          text-align: center;
-        }
-
-        .unit {
-          color: #ffffffbb;
-          font-size: 13px;
-        }
-      }
-    }
-    .title {
-      text-align: center;
-    }
-  }
-  .left-box {
-    width: 360px;
-  }
-  .gas-pump-item {
-    padding: 3px 0;
-  }
-
-  .param-set {
-    color: #45d3fd;
-    cursor: pointer;
-    &:hover {
-      color: #38a6c8;
-    }
-  }
-
-  .input-item {
-    margin: 3px 0 !important;
-    .value {
-      width: 80px;
-      text-align: center;
-    }
-  }
-  .data-group {
-    display: flex;
-    flex-wrap: wrap;
-    justify-content: space-between;
-    padding-bottom: 8px;
-    .data-item {
-      width: calc(50% - 10px);
-      display: flex;
-      justify-content: space-between;
-      line-height: 24px;
-      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
-      margin: 4px 0;
-    }
-    .value {
-      color: #00eefffe;
-    }
-    .data-item1 {
-      width: 100%;
-      line-height: 24px;
-      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
-      margin: 4px 0;
-    }
-  }
-
-  .base-title {
-    line-height: 26px;
-    position: relative;
-    padding-left: 15px;
-    color: #9bf2ff;
-    &::after {
-      content: '';
-      position: absolute;
-      display: block;
-      width: 4px;
-      height: 12px;
-      top: 8px;
-      left: 5px;
-      background: #45d3fd;
-      border-radius: 4px;
-    }
-  }
-
-  .detail {
-    border: 1px solid #9bf2ff88;
-    padding: 0 5px;
-    background-color: #ffffff11;
-    margin-right: 4px;
-    &:hover {
-      background-color: #ffffff05;
-    }
+  .point-event {
+    pointer-events: none !important;
   }
 </style>

+ 45 - 35
src/views/vent/gas/gasAssessment/threejs/gasAssessmen.threejs.base.ts

@@ -8,6 +8,11 @@ import { green, yellow } from '@ant-design/colors';
 // import * as dat from 'dat.gui';
 // const gui = new dat.GUI();
 // gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+type Unit = {
+  id: string;
+  ratio: number;
+  color: THREE.Color;
+};
 
 class GasAssessmen {
   model;
@@ -32,7 +37,7 @@ class GasAssessmen {
   playerStartClickTime1 = new Date().getTime();
   playerStartClickTime2 = new Date().getTime();
   planeNum = 0;
-  unitList = [];
+  unitList: Unit[] = [];
 
   constructor(model) {
     this.model = model;
@@ -82,27 +87,27 @@ class GasAssessmen {
 
     const sizeList = [
       {
-        id: '',
+        id: '111',
         ratio: 0.2,
         color: colors.c1,
       },
       {
-        id: '',
+        id: '222',
         ratio: 0.3,
         color: colors.c2,
       },
       {
-        id: '',
+        id: '333',
         ratio: 0.1,
         color: colors.c4,
       },
       {
-        id: '',
+        id: '444',
         ratio: 0.2,
         color: colors.c5,
       },
       {
-        id: '',
+        id: '555',
         ratio: 0.2,
         color: colors.c3,
       },
@@ -228,6 +233,7 @@ class GasAssessmen {
     const plane = new THREE.Mesh(geometry, material);
     plane.rotation.x = -Math.PI / 2;
     plane.position.set(-0.2, 0.15, -0.03);
+    plane.name = 'unit';
     this.planeGroup.add(plane);
     this.group.add(this.planeGroup);
   };
@@ -294,37 +300,42 @@ class GasAssessmen {
   };
 
   /* 点击 */
-  mousedownModel(rayCaster: THREE.Raycaster) {
-    const intersects = rayCaster?.intersectObjects([...this.planeGroup.children]) as THREE.Intersection[];
-
+  mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
     // 判断是否点击到视频
-    intersects.find((intersect) => {
-      const intersectedObject = intersects[0].object;
-
-      // 如果对象是我们的平面,并且它有自定义属性来标识它的 UV 范围
-      if (intersectedObject && intersectedObject.material && intersectedObject.material.uniforms) {
-        const uv = intersects[0].uv; // 点击点的 UV 坐标
-        const clickedRatio = uv.x; // 使用 UV 的 x 分量作为比例值
-
-        // // 根据点击的比例找到对应的色块
-        // let clickedColorIndex = -1;
-        // for (let i = 0; i < accumulatedRatios.length - 1; i++) {
-        //   if (clickedRatio >= accumulatedRatios[i] && clickedRatio < accumulatedRatios[i + 1]) {
-        //     clickedColorIndex = i;
-        //     break;
-        //   }
-        // }
-
-        // if (clickedColorIndex !== -1) {
-        //   // 提供反馈,例如打印信息到控制台
-        //   console.log(`Clicked color block ${clickedColorIndex}:`, sizeList[clickedColorIndex]);
+    return new Promise((resolve) => {
+      intersects.find((intersect) => {
+        const intersectedObject = intersect.object;
+        if (intersectedObject.name == 'unit') {
+          // 如果对象是我们的平面,并且它有自定义属性来标识它的 UV 范围
+          if (intersectedObject && intersectedObject.material && intersectedObject.material.uniforms) {
+            const uv = intersect.uv; // 点击点的 UV 坐标
+            const clickedRatio = uv.x; // 使用 UV 的 x 分量作为比例值
+
+            // 根据点击的比例找到对应的色块
+            let clickedColorIndex = -1;
+            let accRatio = 0;
+            for (let i = 0; i < this.unitList.length - 1; i++) {
+              const unitData = this.unitList[i];
+              accRatio += unitData.ratio;
+              if (clickedRatio < accRatio) {
+                clickedColorIndex = i;
+                break;
+              }
+            }
 
-        //   // 这里你可以做更多事情,如改变颜色、显示弹窗等
-        // }
-      }
-      return false;
+            if (clickedColorIndex !== -1) {
+              const unitData = this.unitList[clickedColorIndex];
+              const unitId = unitData.id;
+              // window.open(`${location.origin}/gasUnitAssessment/home?id=${unitId}`);
+              resolve(unitId);
+            }
+          }
+          return true;
+        }
+        return false;
+      });
+      this.render();
     });
-    this.render();
   }
 
   mouseUpModel() {
@@ -343,7 +354,6 @@ class GasAssessmen {
         });
         this.group.name = this.modelName;
         this.addLight();
-
         resolve(null);
       });
     });

+ 90 - 29
src/views/vent/gas/gasAssessment/threejs/gasAssessmen.threejs.ts

@@ -1,40 +1,43 @@
 import * as THREE from 'three';
 import UseThree from '@/utils/threejs/useThree';
 import GasAssessmen from './gasAssessmen.threejs.base';
-import { animateCamera } from '/@/utils/threejs/util';
+import GasUnit from './gasUnit.threejs.base';
+import { animateCamera, setModalCenter } from '/@/utils/threejs/util';
 import useEvent from '@/utils/threejs/useEvent';
+import gsap from 'gsap';
+import { Ref } from 'vue';
 
 // 模型对象、 文字对象
-let model,
-  workFaceObj: GasAssessmen | undefined,
-  group,
-  fiberType = 'workFace'; // workerFaceFiber
-
-const { mouseDownFn, mousemoveFn, mouseUpFn } = useEvent();
+let model, workFaceObj: GasAssessmen | undefined, gasUnit: GasUnit | undefined, group;
+let modalType: Ref<string>;
+let activeId: Ref<string>;
+const { mouseDownFn } = useEvent();
 
 // 鼠标点击、松开事件
 const mouseEvent = (event) => {
   if (event.button == 0 && group) {
-    model.canvasContainer?.addEventListener('mousemove', mousemove);
-    // const groud = group.getObjectByName('groud');
-    // const intakewind = group.getObjectByName('workFace-jin');
-    // const returnwind = group.getObjectByName('workFace-hui');
-    // mouseDownFn(model, [groud, intakewind, returnwind], event);
-    console.log('摄像头控制信息', model.orbitControls, model.camera);
+    if (modalType?.value == 'workFace') {
+      mouseDownFn(<UseThree>model, <THREE.Object3D>workFaceObj?.planeGroup, event, (intersects) => {
+        workFaceObj?.mousedownModel(intersects).then(async (unitId: string) => {
+          if (activeId) activeId.value = unitId;
+          await setModelType('toUnit');
+        });
+      });
+    } else if (modalType?.value == 'gasUnit') {
+      mouseDownFn(<UseThree>model, <THREE.Object3D>gasUnit?.group, event, (intersects) => {
+        gasUnit?.mousedownModel(intersects).then(async () => {
+          await setModelType('toWorkFace');
+        });
+      });
+    }
   }
 };
 
 const mouseUp = () => {
   if (!model) return;
-  model.canvasContainer?.removeEventListener('mousemove', mousemove);
-  mouseUpFn(model, 0.2);
   workFaceObj?.mouseUpModel.call(workFaceObj);
 };
 
-const mousemove = () => {
-  mousemoveFn();
-};
-
 const addMouseEvent = () => {
   // 定义鼠标点击事件
   model.canvasContainer?.addEventListener('mousedown', mouseEvent.bind(null));
@@ -60,19 +63,72 @@ export const clearCss3D = () => {
 };
 
 // 切换风窗类型
-export const setModelType = (type, n = Math.ceil(Math.random() * 4), isShowPlane) => {
-  fiberType = type;
+export const setModelType = (type, n = Math.ceil(Math.random() * 4)) => {
   return new Promise((resolve) => {
-    if (workFaceObj) {
-      workFaceObj.clearPlanes();
+    const newCameraPosition = { x: -0.1077663653208413, y: 3.730662630250735, z: 5.174545297338427 };
+    const newControlsPosition = { x: -0.0997084705839992, y: -0.050186843433472336, z: -0.3263852289773498 };
+
+    if (type == 'toUnit' && workFaceObj && gasUnit) {
+      if (modalType) modalType.value = 'gasUnit';
+      gsap.to(workFaceObj.group.scale, {
+        x: 30,
+        y: 30,
+        z: 30,
+        duration: 1,
+        ease: 'easeInCirc',
+        onComplete: function () {
+          gasUnit.group.scale.set(20, 20, 20);
+          workFaceObj.group.visible = false;
+          setModalCenter(gasUnit.group);
+          gasUnit.group.visible = true;
+          const newCameraPosition1 = { x: 0.07728832423767938, y: 2.000608719643587, z: 3.920565793165089 };
+          const newControlsPosition1 = { x: 0.08291552616960282, y: -0.6396998462924676, z: 0.07906121096410117 };
+          animateCamera(newCameraPosition, newControlsPosition, newCameraPosition1, newControlsPosition1, model, 0.8);
+          gsap.to(gasUnit.group.scale, {
+            x: 1,
+            y: 1,
+            z: 1,
+            duration: 2,
+            ease: 'easeOutCubic',
+            onComplete: function () {},
+          });
+        },
+      });
+    } else if (type == 'toWorkFace') {
+      // 由抽采单元切换到工作面
+      gsap.to(gasUnit.group.scale, {
+        x: 20,
+        y: 20,
+        z: 20,
+        duration: 1,
+        ease: 'easeInCirc',
+        onComplete: function () {
+          workFaceObj.group.scale.set(20, 20, 20);
+          gasUnit.group.visible = false;
+          setModalCenter(workFaceObj.group);
+          workFaceObj.group.visible = true;
+          const newCameraPosition1 = { x: 0.07728832423767938, y: 2.000608719643587, z: 3.920565793165089 };
+          const newControlsPosition1 = { x: 0.08291552616960282, y: -0.6396998462924676, z: 0.07906121096410117 };
+          animateCamera(newCameraPosition1, newControlsPosition1, newCameraPosition, newControlsPosition, model, 0.8);
+          gsap.to(workFaceObj.group.scale, {
+            x: 1,
+            y: 1,
+            z: 1,
+            duration: 1,
+            ease: 'easeOutCubic',
+            onComplete: function () {
+              if (modalType) modalType.value = 'workFace';
+            },
+          });
+        },
+      });
+    } else {
+      // 初始加载
       group = workFaceObj.group;
-
       workFaceObj?.setPlanes(n);
       showOrHideGasPlane(true);
       const oldControlsPosition = { x: -0.086221, y: -0.612538, z: 0.33468 };
       const oldCameraPosition = { x: 19.589025920044726, y: 7.437905524957071, z: 23.032636074396976 };
-      const newCameraPosition = { x: -0.04789909089889121, y: 3.641517536555166, z: 4.83092458651697 };
-      const newControlsPosition = { x: -0.04024406809413058, y: 0.04971078294784826, z: -0.39495921220738645 };
 
       if (model.scene.getObjectByName('workFace')) {
         model.camera.position.set(oldCameraPosition.x, oldCameraPosition.y, oldCameraPosition.z + 20);
@@ -81,9 +137,9 @@ export const setModelType = (type, n = Math.ceil(Math.random() * 4), isShowPlane
       setTimeout(async () => {
         resolve(null);
         if (!model.scene.getObjectByName('workFace')) {
-          model.scene.add(workFaceObj?.group);
+          model.scene.add(group);
+          model.scene.add(gasUnit.group);
         }
-
         await animateCamera(oldCameraPosition, oldControlsPosition, newCameraPosition, newControlsPosition, model, 0.8);
       }, 600);
     }
@@ -100,7 +156,9 @@ export const showOrHideGasPlane = (isShowPlane) => {
   }
 };
 
-export const mountedThree = () => {
+export const mountedThree = (pageType: Ref<string>, activeUnitId: Ref<string>) => {
+  modalType = pageType;
+  activeId = activeUnitId;
   return new Promise(async (resolve) => {
     model = new UseThree('#workFace3D', '#workFace3DCSS');
     model.setEnvMap('test1');
@@ -109,6 +167,9 @@ export const mountedThree = () => {
     workFaceObj = new GasAssessmen(model);
     await workFaceObj.mountedThree();
 
+    gasUnit = new GasUnit(model);
+    await gasUnit.mountedThree();
+
     addMouseEvent();
     render();
     resolve(null);

+ 105 - 0
src/views/vent/gas/gasAssessment/threejs/gasUnit.threejs.base.ts

@@ -0,0 +1,105 @@
+import * as THREE from 'three';
+import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
+import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
+import { setModalCenter, setTag3D, gradientColors } from '/@/utils/threejs/util';
+import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
+
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+type Unit = {
+  id: string;
+  ratio: number;
+  color: THREE.Color;
+};
+
+class GasUnit {
+  model;
+  modelName = 'gasUnit';
+  group: THREE.Object3D = new THREE.Object3D();
+  planeGroup: THREE.Group = new THREE.Group();
+
+  constructor(model) {
+    this.model = model;
+    this.group.name = this.modelName;
+  }
+  addLight() {
+    // const _this = this;
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
+    directionalLight.position.set(-196, 150, 258);
+    this.group.add(directionalLight);
+    directionalLight.target = this.group;
+  }
+  /* 点击 */
+  mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
+    // 判断是否点击到视频
+    return new Promise((resolve) => {
+      intersects.find((intersect) => {
+        const intersectedObject = intersect.object;
+        if (intersectedObject.name == 'wangge1') {
+          // 如果对象是我们的平面,并且它有自定义属性来标识它的 UV 范围
+          resolve(null);
+          return true;
+        }
+        return false;
+      });
+      this.render();
+    });
+  }
+  render() {
+    this.model.renderer?.render(this.model.scene as THREE.Scene, this.model.camera as THREE.PerspectiveCamera);
+  }
+  // 绘制抽采单元
+  setPlanes = () => {
+    const colors = {
+      c1: new THREE.Color(0x00fe00), // >90
+      c2: new THREE.Color(0xf9b866), // >75 <90  249,184,102
+      c3: new THREE.Color(0xfefe00), // 50-75  254,254,0
+      c4: new THREE.Color(0xfe6600), // 25-50 254,102,0
+      c5: new THREE.Color(0xb00101), // <25 176,1,1
+    };
+    const planeGeo = new THREE.PlaneGeometry();
+    planeGeo.applyMatrix4(new THREE.Matrix4().makeTranslation(-1, 0, 0));
+    const material = new THREE.MeshBasicMaterial({ color: colors[0], transparent: true, opacity: 0.6, depthTest: false, depthWrite: false });
+    const plane = new THREE.Mesh(planeGeo, material);
+    plane.name = 'unit';
+    plane.rotation.x = -Math.PI / 2;
+    plane.scale.set(1, 0.375, 1.0);
+    plane.position.set(0, 0.015, 0.142);
+    this.planeGroup.add(plane);
+    this.group.add(this.planeGroup);
+  };
+
+  mouseUpModel() {
+    //
+  }
+
+  mountedThree() {
+    return new Promise(async (resolve) => {
+      this.model.renderer.sortObjects = true;
+      this.model.orbitControls.update();
+      this.model.setGLTFModel(['gasUnit'], this.group).then(async () => {
+        this.group.children.forEach((object: THREE.Object3D) => {
+          if (object.name.startsWith('gasUnit')) {
+            setModalCenter(object);
+          }
+        });
+        this.group.name = this.modelName;
+        this.group.visible = false;
+        this.addLight();
+        // this.group.scale.set(0.1, 0.1, 0.1);
+        // this.model.setGLTFModel(['workFace1'], this.group).then(async () => {});
+
+        resolve(null);
+      });
+    });
+  }
+
+  destroy() {
+    this.model.clearGroup(this.group);
+    this.model = null;
+    this.group = null;
+  }
+}
+
+export default GasUnit;

+ 13 - 6
src/views/vent/home/configurable/components/detail/CustomChart.vue

@@ -9,6 +9,7 @@
   import { EChartsOption, graphic } from 'echarts';
   import { getData, getFormattedText } from '../../hooks/helper';
   import { install$10 } from 'echarts/types/dist/shared';
+  import { color } from 'echarts/core';
 
   const props = withDefaults(
     defineProps<{
@@ -55,7 +56,7 @@
     }
 
     // 该项作为下面所有图表依赖的基准系列数据
-    const baseSeries: { name: string; data: [string, string][] }[] = sorttedData.reduce((res: any[], baseData) => {
+    const baseSeries: { name: string; data: [string, string][]; color: string }[] = sorttedData.reduce((res: any[], baseData) => {
       series.forEach((serie) => {
         res.push({
           name: getFormattedText(baseData, serie.label),
@@ -63,6 +64,7 @@
             return [getData(data, serie.xprop), getData(data, serie.yprop)]; /** x y */
             // return { name: getData(data, serie.xprop), value: getData(data, serie.yprop) }; /** x y */
           }),
+          color: serie.color,
         });
       });
 
@@ -406,19 +408,24 @@
         }),
         series: baseSeries.map((serie, index) => {
           const colors = ['#66ffff', '#6666ff'];
-
+          let color;
+          if (serie.color) {
+            color = serie.color;
+          } else {
+            color = colors[index % colors.length];
+          }
           return {
             ...serie,
             type: 'line',
             symbol: 'none',
             endLabel: { distance: 0 },
-            lineStyle: { color: colors[index % colors.length] },
+            lineStyle: { color: color },
             areaStyle: {
               origin: 'auto',
               color: new graphic.LinearGradient(0, 0, 0, 1, [
-                { offset: 0, color: colors[index % colors.length] },
-                { offset: 0.2, color: colors[index % colors.length] },
-                { offset: 1, color: `${colors[index % colors.length]}22` },
+                { offset: 0, color: color },
+                { offset: 0.2, color: color },
+                { offset: 1, color: `${color}22` },
               ]),
             },
           };

+ 3 - 1
src/views/vent/monitorManager/balancePressMonitor/components/balancePressHome.vue

@@ -188,7 +188,9 @@
   @import '/@/design/vent/modal.less';
   @import '../../comment/less/workFace.less';
   @ventSpace: zxm;
-
+  .monitor-container {
+    margin-top: 60px;
+  }
   .lr {
     width: 340px !important;
   }

+ 2 - 1
src/views/vent/monitorManager/balancePressMonitor/index.vue

@@ -1,4 +1,5 @@
 <template>
+  <customHeader :fieldNames="{ label: 'systemname', value: 'id', options: 'children' }" :options = 'options' @change="getSelectRow" :optionValue="optionValue">均压与低氧管控</customHeader>
   <div class="bg"
     style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden">
     <a-spin :spinning="loading" />
@@ -17,7 +18,6 @@
     </div> -->
   </div>
   <div class="scene-box">
-    <customHeader :fieldNames="{ label: 'systemname', value: 'id', options: 'children' }" :options = 'options' @change="getSelectRow" :optionValue="optionValue">均压与低氧管控</customHeader>
     <div class="center-container">
       <balancePressHome v-if="activeKey == 'monitor'" :deviceId = 'optionValue' />
       <div v-else class="history-group">
@@ -134,6 +134,7 @@ onUnmounted(() => {
 @import '/@/design/vent/modal.less';
 @ventSpace: zxm;
 .scene-box{
+  margin-top: 20px;
   pointer-events: none;
   .history-group{
     padding: 0 20px;

+ 2 - 1
src/views/vent/monitorManager/beltTunMonitor/index.vue

@@ -1,4 +1,5 @@
 <template>
+  <customHeader :fieldNames="{ label: 'systemname', value: 'id', options: 'children' }" :options = 'options' @change="getSelectRow" :optionValue="optionValue">皮带巷智能管控</customHeader>
   <div
     v-show="activeKey == 'monitor' && !loading" 
     class="bg"
@@ -14,7 +15,6 @@
     <div id="beltTun3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden"> </div>
   </div>
   <div class="scene-box">
-    <customHeader :fieldNames="{ label: 'systemname', value: 'id', options: 'children' }" :options = 'options' @change="getSelectRow" :optionValue="optionValue">皮带巷智能管控</customHeader>
     <div class="center-container">
       <template v-if="activeKey == 'monitor'">
         <div class="monitor-nav">
@@ -192,6 +192,7 @@ onUnmounted(() => {
 .scene-box{
   width: 100%;
   height: 100%;
+  margin-top: 30px;
 }
 .monitor-nav{
   width: 860px;

+ 2 - 1
src/views/vent/monitorManager/chamberMonitor/index.vue

@@ -1,4 +1,5 @@
 <template>
+  <customHeader :fieldNames="{ label: 'strinstallpos', value: 'deviceID', options: 'children' }" :options = 'options' @change="getSelectRow" :optionValue="optionValue">硐室监测管控</customHeader>
   <div class="bg"
     style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden">
     <a-spin :spinning="loading" />
@@ -17,7 +18,6 @@
     </div> -->
   </div>
   <div class="scene-box">
-    <customHeader :fieldNames="{ label: 'strinstallpos', value: 'deviceID', options: 'children' }" :options = 'options' @change="getSelectRow" :optionValue="optionValue">硐室监测管控</customHeader>
     <div class="center-container">
       <chamberHome v-if="activeKey == 'monitor'" :deviceId = 'optionValue' />
       <div v-else class="history-group">
@@ -152,6 +152,7 @@ onUnmounted(() => {
 @import '/@/design/vent/modal.less';
 @ventSpace: zxm;
 .scene-box{
+  margin-top: 20px;
   pointer-events: none;
   .history-group{
     padding: 0 20px;

ファイルの差分が大きいため隠しています
+ 708 - 719
src/views/vent/safetyList/common/detail.vue


+ 1 - 1
src/views/vent/sys/setting/setting.data.ts

@@ -57,7 +57,7 @@ export const formSchema: FormSchema[] = [
     label: '系统风格',
     component: 'RadioGroup',
     defaultValue: 1,
-    show: false,
+    required: true,
     componentProps: {
       options: [
         {

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません