hongrunxia 3 недель назад
Родитель
Сommit
992ff64f59

BIN
public/sparyVideo.mp4


+ 258 - 0
src/views/vent/deviceManager/comment/DeviceModalLeather.vue

@@ -0,0 +1,258 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="registerModalLeather"
+    :title="title"
+    width="1000px"
+    :showCancelBtn="false"
+    :showOkBtn="false"
+    :footer="null"
+    :destroyOnClose="true"
+    :mask-closable="false"
+    @cancel="closeModalFn"
+  >
+    <a-tabs v-if="props.showTab" v-model:activeKey="activeKey">
+      <a-tab-pane key="1" tab="基本信息" force-render>
+        <FormModal :deviceType="deviceType" :record="deviceData" @save-or-update="(values) => emit('saveOrUpdate', values)" />
+      </a-tab-pane>
+      <!-- <a-tab-pane key="10" v-if="deviceType == 'fanlocal' || deviceType == 'fanmain'" tab="风机曲线" force-render>
+        <FanLineModal :record="deviceData" />
+      </a-tab-pane> -->
+      <a-tab-pane key="11" tab="报表录入">
+        <DeviceReportInfo v-if="activeKey == '11'" />
+      </a-tab-pane>
+      <a-tab-pane key="2" tab="点表关联">
+        <PointTable
+          :columns="pointColumns"
+          :pointType="deviceData.strtype"
+          :deviceId="deviceData.id"
+          :valuetype="9"
+          @save="savePointData"
+          @delete="deletePointById"
+        />
+      </a-tab-pane>
+      <a-tab-pane key="8" tab="虚拟点表配置">
+        <PointTable
+          :columns="simulationColumns"
+          :pointType="deviceData.strtype"
+          :deviceId="deviceData.id"
+          :valuetype="4"
+          @save="savePointData"
+          @delete="deletePointById"
+        />
+      </a-tab-pane>
+      <a-tab-pane key="3" tab="关联设备" v-if="deviceType == 'managesys'">
+        <WorkFacePointTable :columns="linkColumns" :deviceId="deviceData.id" @save="savePointData" @delete="deletePointById" />
+      </a-tab-pane>
+      <a-tab-pane key="12" tab="关联报表" v-if="deviceType == 'managesys'">
+        <WorkFaceReportTable :columns="reportColumns" :device="deviceData" />
+      </a-tab-pane>
+      <a-tab-pane v-if="deviceType == 'managesys'" key="4" tab="预警条目管理">
+        <ManagerWarningDeviceTable v-if="activeKey == '4'" :deviceId="deviceData.id" />
+      </a-tab-pane>
+      <a-tab-pane v-if="deviceType == 'managesys'" key="14" tab="配置预警解除后控制设备">
+        <template v-if="activeKey == '14'">
+          <ManagerWarningTable :deviceId="deviceData.id" :monitor-type="3" />
+        </template>
+      </a-tab-pane>
+      <a-tab-pane key="7" tab="摄像头配置">
+        <EditRowTable
+          :columns="cameraColumns"
+          :list="cameraList"
+          :params="{ deviceid: deviceData.id }"
+          @save-or-update="saveCameraData"
+          @delete-by-id="deleteCameraById"
+          :isAdd="true"
+        />
+      </a-tab-pane>
+      <a-tab-pane key="9" :tab="'预案管理'">
+        <AccidentPlanTable :deviceId="deviceData.id" />
+      </a-tab-pane>
+      <a-tab-pane v-if="deviceType == 'led'" key="10" :tab="'节目管理'">
+        <LEDPlaylistTable :deviceId="deviceData.id" />
+      </a-tab-pane>
+
+      <a-tab-pane key="13" :tab="'故障配置管理'">
+        <FaultConfigTable :deviceId="deviceData.id" />
+      </a-tab-pane>
+
+      <!-- <a-tab-pane key="9" tab="预警指标修改">
+        <template v-if="activeKey == '9'">
+        <editWarnTable></editWarnTable>
+        </template>
+      </a-tab-pane> -->
+    </a-tabs>
+    <FormModal v-else :record="record" @save-or-update="(values) => emit('saveOrUpdate', values)" />
+  </BasicModal>
+</template>
+<script lang="ts" setup>
+import { computed, unref, inject, reactive, ref, watch } from 'vue';
+import { BasicModal, useModalInner } from '/@/components/Modal';
+import EditRowTable from '../../comment/EditRowTable.vue';
+import PointTable from './pointTabel/PointTable.vue';
+import WarningTable from './warningTabel/index.vue';
+import ManagerWarningTable from './warningTabel/index1.vue';
+import ManagerWarningDeviceTable from './warningTabel/indexLeather.vue';
+import BackWindDeviceTable from './warningTabel/index3.vue';
+import AccidentPlanTable from './warningTabel/index4.vue';
+import LEDPlaylistTable from './warningTabel/index5.vue';
+import WorkFacePointTable from './pointTabel/WorkFacePointTable.vue';
+import WorkFaceReportTable from './pointTabel/WorkFaceReportTable.vue';
+import DeviceReportInfo from './DeviceReportInfo.vue';
+import FaultConfigTable from './faultConfigTable/index.vue';
+// import editWarnTable from './editWarnTable/index.vue'
+import FanLineModal from './FanLineModal .vue';
+import FormModal from './FormModal.vue';
+import { cloneDeep } from 'lodash-es';
+import { columns as pointColumns, workFaceColumns, simulationColumns, reportColumns } from './pointTabel/point.data';
+import { saveOrUpdate as pointSaveOrUpdate, deleteById as pointDeleteById } from './pointTabel/point.api';
+import { columns as cameraColumns } from './cameraTabel/camera.data';
+
+import { list as cameraList, saveOrUpdate as cameraSaveOrUpdate, deleteById as cameraDeleteById } from './cameraTabel/camera.api';
+
+const props = defineProps({
+  showTab: { type: Boolean, required: true },
+  // deviceType: { type: String },
+});
+// 声明Emits
+const emit = defineEmits(['saveOrUpdate', 'register', 'closeModal']);
+const isUpdate = inject('isUpdate');
+const deviceData = inject('formData') as any;
+const deviceType = inject('deviceType') as any;
+const record = reactive({});
+const activeKey = ref('1');
+const linkColumns = ref<any[]>([]);
+
+const [registerModalLeather, { setModalProps, closeModal: closeModalLeather }] = useModalInner(async (data) => {
+  setModalProps({ confirmLoading: false });
+  Object.assign(deviceData, data.record);
+});
+
+//设置标题
+const title = computed(() => {
+  if (!unref(isUpdate)) {
+    if (deviceData.strname || deviceData.systemname) {
+      return `新增(${deviceData.strname || deviceData.systemname})`;
+    }
+    return `新增`;
+  } else {
+    if (deviceData['strtype'] == 'sys_majorpath') {
+      linkColumns.value = [
+        ...workFaceColumns,
+        ...[
+          {
+            title: '是否在关键通风路线上',
+            width: 100,
+            dataIndex: 'pathflag',
+            edit: true,
+            editComponent: 'Switch',
+            editValueMap: (value) => {
+              return value ? '是' : '否';
+            },
+          },
+          {
+            title: '传感器类型',
+            width: 100,
+            dataIndex: 'sensorType',
+            edit: true,
+            editComponent: 'Select',
+            editComponentProps: {
+              options: [
+                {
+                  label: '多参',
+                  value: '1',
+                },
+                {
+                  label: '测风',
+                  value: '2',
+                },
+              ],
+            },
+          },
+          {
+            title: '风向',
+            width: 100,
+            dataIndex: 'winddir',
+            edit: true,
+            editComponent: 'Select',
+            editComponentProps: {
+              options: [
+                {
+                  label: '进风',
+                  value: '1',
+                },
+                {
+                  label: '用风',
+                  value: '2',
+                },
+                {
+                  label: '回风',
+                  value: '3',
+                },
+              ],
+            },
+          },
+          {
+            title: '是否总风量',
+            width: 100,
+            dataIndex: 'windflag',
+            edit: true,
+            editComponent: 'Switch',
+            editValueMap: (value) => {
+              return value ? '是' : '否';
+            },
+          },
+          {
+            title: '路线名称',
+            width: 100,
+            dataIndex: 'des',
+            edit: true,
+            editComponent: 'Input',
+          },
+          {
+            title: ' 阻力值',
+            width: 100,
+            dataIndex: 'testDrag',
+            edit: true,
+            editComponent: 'InputNumber',
+          },
+        ],
+      ];
+    } else {
+      linkColumns.value = [...workFaceColumns];
+    }
+    if (deviceData.strname || deviceData.systemname) {
+      return `编辑(${deviceData.strname || deviceData.systemname})`;
+    }
+    return `编辑`;
+  }
+});
+
+const closeModalFn = () => {
+  activeKey.value = '1';
+  closeModalLeather();
+  emit('closeModal');
+};
+
+const savePointData = (data) => {
+  const record = cloneDeep(data.editValueRefs);
+  pointSaveOrUpdate(Object.assign(record, { id: data.id, deviceId: deviceData.id }), data.id);
+};
+const saveCameraData = (data: any, reload: Function) => {
+  cameraSaveOrUpdate(Object.assign({ ...data }, { id: data.id, deviceid: deviceData.id }), data.id);
+};
+const deletePointById = (id, reload) => {
+  pointDeleteById({ id: id }, reload);
+};
+const deleteCameraById = (id, reload) => {
+  cameraDeleteById({ id: id }, reload);
+};
+</script>
+<style scoped lang="less">
+::v-deep .suffix {
+  height: 32px;
+  line-height: 32px;
+  margin-left: 5px;
+  color: #fff;
+}
+</style>

+ 185 - 0
src/views/vent/deviceManager/comment/warningTabel/BaseModal1Leather.vue

@@ -0,0 +1,185 @@
+<template>
+  <BasicModal @register="register" :title="title" :width="1600" :min-height="500" v-bind="$attrs" @ok="onSubmit">
+    <!-- 顶部基础表单 -->
+    <BasicForm @register="registerForm" />
+
+    <!-- 左右分栏:预警配置 + 控制配置 -->
+    <div class="double-form__layout">
+      <!-- 左侧:配置预警设备 -->
+      <div class="setting-form__wrapper">
+        <h3 class="panel-title">配置预警设备</h3>
+        <div class="form-row" v-for="(item, idx) in warnList" :key="`warn-${idx}`">
+          <BasicForm :model="item" :schemas="deviceFormColumns" layout="inline" label-width="0" :show-action-button-group="false" />
+          <a-button type="link" normal @click="delWarnRow(idx)" :disabled="warnList.length <= 1">删除</a-button>
+        </div>
+        <a-button type="dashed" block @click="addWarnRow" class="setting-form__button">新增预警配置</a-button>
+      </div>
+
+      <!-- 右侧:配置控制设备 -->
+      <div class="setting-form__wrapper">
+        <h3 class="panel-title">配置控制设备</h3>
+        <div class="form-row" v-for="(item, idx) in controlList" :key="`control-${idx}`">
+          <BasicForm :model="item" :schemas="deviceControlColumns" layout="inline" label-width="0" :show-action-button-group="false" />
+          <a-button type="link" normal @click="delControlRow(idx)" :disabled="controlList.length <= 1">删除</a-button>
+        </div>
+        <a-button type="dashed" block @click="addControlRow" class="setting-form__button">新增控制配置</a-button>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+import { ref, unref } from 'vue';
+import { BasicForm, useForm } from '/@/components/Form';
+import { BasicModal, useModalInner } from '/@/components/Modal';
+import { message } from 'ant-design-vue';
+import { deviceFormColumns, deviceControlColumns } from './warning.data';
+import type { FormSchema } from '/@/components/Form/src/types/form';
+
+const props = defineProps({
+  formSchemas: {
+    type: Array as PropType<FormSchema[]>,
+    default: () => [],
+  },
+  deviceId: String,
+  monitorType: String,
+});
+
+const emit = defineEmits(['add', 'update']);
+const title = ref('');
+const isUpdate = ref(false);
+
+// ==========================================
+//  左侧:预警配置列表(独立)
+// ==========================================
+const warnList = ref([getEmptyWarnRow()]);
+function getEmptyWarnRow() {
+  return {
+    deviceType: '',
+    monitorId: '',
+    fmax: null,
+    fmin: null,
+    cxTime: null,
+    dataTrend: '',
+    trendCxTime: null,
+  };
+}
+function addWarnRow() {
+  warnList.value.push(getEmptyWarnRow());
+}
+function delWarnRow(idx) {
+  if (warnList.value.length <= 1) return message.warning('至少保留一行');
+  warnList.value.splice(idx, 1);
+}
+
+// ==========================================
+//  右侧:控制配置列表(独立)
+// ==========================================
+const controlList = ref([getEmptyControlRow()]);
+function getEmptyControlRow() {
+  return {
+    deviceType: '',
+    monitorId: '',
+    value: '',
+    orderNum: null,
+    remark: '',
+  };
+}
+function addControlRow() {
+  controlList.value.push(getEmptyControlRow());
+}
+function delControlRow(idx) {
+  if (controlList.value.length <= 1) return message.warning('至少保留一行');
+  controlList.value.splice(idx, 1);
+}
+
+// ==========================================
+//  主表单 & 弹窗
+// ==========================================
+const [registerForm, { resetFields, setFieldsValue, validate, getFieldsValue }] = useForm({
+  schemas: props.formSchemas,
+  showActionButtonGroup: false,
+});
+
+const [register, { setModalProps, closeModal }] = useModalInner(async (data) => {
+  isUpdate.value = unref(data.isUpdate);
+  title.value = data.isUpdate ? '编辑预警' : '新增预警';
+  await resetFields();
+
+  if (data.isUpdate && data.record) {
+    await setFieldsValue(data.record);
+    // 编辑回显 两组数据
+    warnList.value = data.record.warnList || [getEmptyWarnRow()];
+    controlList.value = data.record.controlList || [getEmptyControlRow()];
+  } else {
+    // 新增重置
+    warnList.value = [getEmptyWarnRow()];
+    controlList.value = [getEmptyControlRow()];
+  }
+});
+
+async function onSubmit() {
+  try {
+    const baseForm = await getFieldsValue();
+    await validate();
+    setModalProps({ confirmLoading: true });
+
+    const submitData = {
+      ...baseForm,
+      warnList: warnList.value, // 预警配置数组
+      controlList: controlList.value, // 控制配置数组
+    };
+
+    emit(isUpdate.value ? 'update' : 'add', isUpdate.value ? 'update' : 'add', submitData);
+    closeModal();
+  } finally {
+    setModalProps({ confirmLoading: false });
+  }
+}
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+@import '/@/design/theme.less';
+
+.setting-form {
+  padding: 0 20px;
+}
+
+.setting-form__wrapper {
+  width: 49%;
+  color: #fff;
+  border-top: 3px solid @vent-gas-primary-text;
+  background-color: @vent-gas-primary-trasparent-bg;
+  padding: 10px 10px 0 10px;
+  margin-bottom: 10px;
+}
+
+.setting-form__button {
+  display: block;
+  width: 40%;
+  margin: 10px auto;
+  color: @vent-gas-primary-text;
+  border-color: @vent-gas-primary-text;
+  background-color: transparent !important;
+}
+.double-form__layout {
+  display: flex;
+  gap: 16px;
+  margin-top: 16px;
+}
+.panel-title {
+  margin: 0 0 10px;
+  font-size: 14px;
+  font-weight: bold;
+  color: #fafafa;
+}
+.form-row {
+  border: 1px solid #2e7695;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 10px;
+  margin-top: 10px;
+}
+</style>

+ 3 - 1
src/views/vent/deviceManager/comment/warningTabel/index1.vue

@@ -20,7 +20,7 @@
       </a-table>
     </div>
   </div>
-  <BaseModal @register="register" @add="onSubmit" @update="onSubmit" :form-schemas="formSchemas" :monitor-type="monitorType" />
+  <BaseModal @register="register" @add="onSubmit" @update="onSubmit" :form-schemas="formSchemas" :monitor-type="valueTypes" />
 </template>
 
 <script lang="ts" setup>
@@ -34,6 +34,8 @@
   const props = defineProps({
     deviceId: { type: String },
     monitorType: { type: Number, default: 1 },
+    /** 获取点位接口的参数 */
+    valueTypes: { type: String, default: '1' },
   });
 
   const formSchemas = controlFormSchemas({ id: props.deviceId });

+ 92 - 85
src/views/vent/deviceManager/comment/warningTabel/index2.vue

@@ -17,107 +17,114 @@
 </template>
 
 <script lang="ts" name="system-user" setup>
-  import { BasicTable, FormSchema } from '/@/components/Table';
-  import { useListPage } from '/@/hooks/system/useListPage';
-  import BaseModal from './BaseModal1.vue';
-  import { useModal } from '/@/components/Modal';
-  import { workFaceWarningColumns, workFaceWarningFormSchemas } from './warning.data';
-  import { warningLogList, warningLogAdd, warningLogEdit, warningLogDeleteById } from './warning.api';
+import { BasicTable, FormSchema } from '/@/components/Table';
+import { useListPage } from '/@/hooks/system/useListPage';
+import BaseModal from './BaseModal1.vue';
+import { useModal } from '/@/components/Modal';
+import { workFaceWarningColumns, workFaceWarningFormSchemas } from './warning.data';
+import { warningLogList, warningLogAdd, warningLogAddLeather, warningLogEdit, warningLogDeleteById } from './warning.api';
 
-  const props = defineProps({
-    deviceId: { type: String },
-  });
+const props = defineProps({
+  deviceId: { type: String },
+});
 
-  const { tableContext } = useListPage({
-    tableProps: {
-      api: warningLogList.bind(null, { sysId: props.deviceId }),
-      scroll: { y: 390 },
-      size: 'small',
-      // expandRowByClick: true,
-      clickToRowSelect: true,
-      useSearchForm: false,
-      rowSelection: {
-        columnWidth: 20,
-      },
-      showTableSetting: false,
-      formConfig: {
-        disabled: true,
-        showResetButton: false,
-        showSubmitButton: false,
-      },
+const { tableContext } = useListPage({
+  tableProps: {
+    api: warningLogList.bind(null, { sysId: props.deviceId }),
+    scroll: { y: 390 },
+    size: 'small',
+    // expandRowByClick: true,
+    clickToRowSelect: true,
+    useSearchForm: false,
+    rowSelection: {
+      columnWidth: 20,
+    },
+    showTableSetting: false,
+    formConfig: {
+      disabled: true,
+      showResetButton: false,
+      showSubmitButton: false,
     },
-  });
-  const [registerTable, { reload }] = tableContext;
+  },
+});
+const [registerTable, { reload }] = tableContext;
 
-  const [register, { openModal, closeModal }] = useModal();
+const [register, { openModal, closeModal }] = useModal();
 
-  function openModalFn(record?) {
-    if (record) {
-      openModal(true, {
-        isUpdate: true,
-        record,
-      });
-    } else {
-      openModal(true, {
-        isUpdate: false,
-      });
-    }
+function openModalFn(record?) {
+  if (record) {
+    openModal(true, {
+      isUpdate: true,
+      record,
+    });
+  } else {
+    openModal(true, {
+      isUpdate: false,
+    });
   }
+}
 
-  async function handleDelete(record) {
-    await warningLogDeleteById(record.id);
-  }
+async function handleDelete(record) {
+  await warningLogDeleteById(record.id);
+}
 
-  async function onSubmit(flag, values) {
-    // 提交数据弹窗
-    if (flag == 'update') {
-      await warningLogEdit(values);
+async function onSubmit(flag, values) {
+  // 提交数据弹窗
+  if (flag == 'update') {
+    await warningLogEdit(values);
+  } else {
+    if (values.alarmType === 'leather_') {
+      // 调用第二个接口
+      await warningLogAddLeather({ ...values, sysId: props.deviceId });
     } else {
+      // 调用默认接口
       await warningLogAdd({ ...values, sysId: props.deviceId });
     }
-    closeModal();
-    //刷新列表
-    reload();
+    // await warningLogAdd({ ...values, sysId: props.deviceId });
   }
+  closeModal();
+  //刷新列表
+  reload();
+}
 
-  const workFaceWarningSchemas: FormSchema[] = [
-    ...workFaceWarningFormSchemas,
-    {
-      label: '关联条目',
-      field: 'relatedEntries',
-      component: 'ApiSelect',
-      componentProps: {
-        labelField: 'alarmName',
-        valueField: 'id',
-        resultField: 'records',
-        api: warningLogList.bind(null, { sysId: props.deviceId }),
-      },
+const workFaceWarningSchemas: FormSchema[] = [
+  ...workFaceWarningFormSchemas,
+  {
+    label: '关联条目',
+    field: 'relatedEntries',
+    component: 'ApiSelect',
+    componentProps: {
+      labelField: 'alarmName',
+      valueField: 'id',
+      resultField: 'records',
+      api: warningLogList.bind(null, { sysId: props.deviceId }),
     },
-    {
-      label: '预警后自动控制',
-      field: 'isAutoControl',
-      component: 'RadioGroup',
-      componentProps: {
-        //options里面由一个一个的radio组成,支持disabled
-        options: [
-          { label: '是', value: true },
-          { label: '否', value: false },
-        ],
-      },
+  },
+  {
+    label: '预警后自动控制',
+    field: 'isAutoControl',
+    component: 'RadioGroup',
+    componentProps: {
+      //options里面由一个一个的radio组成,支持disabled
+      options: [
+        { label: '是', value: true },
+        { label: '否', value: false },
+      ],
     },
-    {
-      label: '解除后自动复位',
-      field: 'isAutoReset',
-      component: 'RadioGroup',
-      componentProps: {
-        //options里面由一个一个的radio组成,支持disabled
-        options: [
-          { label: '是', value: true },
-          { label: '否', value: false },
-        ],
-      },
+  },
+  {
+    label: '解除后自动复位',
+    field: 'isAutoReset',
+    component: 'RadioGroup',
+    componentProps: {
+      //options里面由一个一个的radio组成,支持disabled
+      options: [
+        { label: '是', value: true },
+        { label: '否', value: false },
+      ],
     },
-  ];
+  },
+];
 </script>
 
 <style scoped></style>

+ 144 - 0
src/views/vent/deviceManager/comment/warningTabel/indexLeather.vue

@@ -0,0 +1,144 @@
+<template>
+  <!-- 预警条目管理 -->
+  <div class="">
+    <BasicTable @register="registerTable" :columns="workFaceWarningColumns">
+      <template #tableTitle>
+        <a-button preIcon="ant-design:plus-outlined" type="primary" @click="openModal(true, {})">新增</a-button>
+      </template>
+      <template #action="{ record }">
+        <a class="table-action-link" @click="openModalFn(record)">编辑</a>
+        <a-popconfirm title="确定删除?" @confirm="handleDelete(record)">
+          <a class="table-action-link">删除</a>
+        </a-popconfirm>
+      </template>
+    </BasicTable>
+    <BaseModal @register="register" @add="onSubmit" @update="onSubmit" :destroy-on-close="true" :form-schemas="workFaceWarningSchemas"> </BaseModal>
+  </div>
+</template>
+
+<script lang="ts" name="system-user" setup>
+import { ref } from 'vue';
+import { BasicTable, FormSchema } from '/@/components/Table';
+import { useListPage } from '/@/hooks/system/useListPage';
+import BaseModal from './BaseModal1Leather.vue';
+import { useModal } from '/@/components/Modal';
+import { workFaceWarningColumns, workFaceWarningFormSchemasLeather, deviceFormColumns } from './warning.data';
+import { warningLogList, warningLogAdd, warningLogAddLeather, warningLogEdit, warningLogDeleteById } from './warning.api';
+
+const props = defineProps({
+  deviceId: { type: String },
+});
+const alarmList = ref<any[]>([]);
+const { tableContext } = useListPage({
+  tableProps: {
+    api: warningLogList.bind(null, { sysId: props.deviceId }),
+    scroll: { y: 390 },
+    size: 'small',
+    // expandRowByClick: true,
+    clickToRowSelect: true,
+    useSearchForm: false,
+    rowSelection: {
+      columnWidth: 20,
+    },
+    showTableSetting: false,
+    formConfig: {
+      disabled: true,
+      showResetButton: false,
+      showSubmitButton: false,
+    },
+  },
+});
+const [registerTable, { reload }] = tableContext;
+
+const [register, { openModal, closeModal }] = useModal();
+
+//  新增一行
+function addDeviceRow() {
+  alarmList.value.push({
+    deviceType: '',
+    upperLimit: null,
+    lowerLimit: null,
+  });
+}
+// 删除一行
+function removeDeviceRow(index: number) {
+  alarmList.value.splice(index, 1);
+}
+function openModalFn(record?) {
+  if (record) {
+    openModal(true, {
+      isUpdate: true,
+      record,
+    });
+  } else {
+    openModal(true, {
+      isUpdate: false,
+    });
+  }
+}
+
+async function handleDelete(record) {
+  await warningLogDeleteById(record.id);
+}
+
+async function onSubmit(flag, values) {
+  // 提交数据弹窗
+  if (flag == 'update') {
+    await warningLogEdit(values);
+  } else {
+    if (values.alarmType === 'leather_') {
+      // 调用第二个接口
+      await warningLogAddLeather({ ...values, sysId: props.deviceId });
+    } else {
+      // 调用默认接口
+      await warningLogAdd({ ...values, sysId: props.deviceId });
+    }
+    // await warningLogAdd({ ...values, sysId: props.deviceId });
+  }
+  closeModal();
+  //刷新列表
+  reload();
+}
+
+const workFaceWarningSchemas: FormSchema[] = [
+  ...workFaceWarningFormSchemasLeather,
+  {
+    label: '关联条目',
+    field: 'relatedEntries',
+    component: 'ApiSelect',
+    componentProps: {
+      labelField: 'alarmName',
+      valueField: 'id',
+      resultField: 'records',
+      api: warningLogList.bind(null, { sysId: props.deviceId }),
+    },
+  },
+  {
+    label: '预警后自动控制',
+    field: 'isAutoControl',
+    component: 'RadioGroup',
+    componentProps: {
+      //options里面由一个一个的radio组成,支持disabled
+      options: [
+        { label: '是', value: true },
+        { label: '否', value: false },
+      ],
+    },
+  },
+  {
+    label: '解除后自动复位',
+    field: 'isAutoReset',
+    component: 'RadioGroup',
+    componentProps: {
+      //options里面由一个一个的radio组成,支持disabled
+      options: [
+        { label: '是', value: true },
+        { label: '否', value: false },
+      ],
+    },
+  },
+];
+</script>
+
+<style scoped>
+</style>

+ 2 - 0
src/views/vent/deviceManager/comment/warningTabel/warning.api.ts

@@ -19,6 +19,7 @@ enum Api {
 
   warningLogList = '/safety/managesysAlarmInfo/list',
   warningLogAdd = '/safety/managesysAlarmInfo/add',
+  warningLogAddLeather = '/safety/managesysAlarmInfo/addLeather',
   warningLogEdit = '/safety/managesysAlarmInfo/edit',
   warningLogDeleteById = '/safety/managesysAlarmInfo/delete/',
 
@@ -141,6 +142,7 @@ export const backWindControlDevicePointDelete = (params) => {
 // 预警条目管理
 export const warningLogList = (params) => defHttp.get({ url: Api.warningLogList, params });
 export const warningLogAdd = (params) => defHttp.post({ url: Api.warningLogAdd, params });
+export const warningLogAddLeather = (params) => defHttp.post({ url: Api.warningLogAddLeather, params });
 export const warningLogEdit = (params) => defHttp.put({ url: Api.warningLogEdit, params });
 export const warningLogDeleteById = (params) => defHttp.delete({ url: Api.warningLogDeleteById, params }, { joinParamsToUrl: true }).then(() => {});
 

+ 128 - 1
src/views/vent/deviceManager/comment/warningTabel/warning.data.ts

@@ -298,7 +298,134 @@ export const workFaceWarningFormSchemas: FormSchema[] = [
     componentProps: { dictCode: 'kindtype' },
   },
 ];
-
+export const workFaceWarningFormSchemasLeather: FormSchema[] = [
+  {
+    label: 'ID',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+  {
+    label: '预警名称',
+    field: 'alarmName',
+    component: 'Input',
+    required: true,
+  },
+  {
+    label: '预警类型',
+    field: 'alarmType',
+    component: 'JDictSelectTag',
+    componentProps: { dictCode: 'alarmType' },
+  },
+  {
+    label: '预警等级',
+    field: 'alarmLevel',
+    component: 'JDictSelectTag',
+    componentProps: { dictCode: 'leveltype', stringToNumber: true },
+    required: true,
+  },
+  {
+    label: '配置预警设备',
+    field: 'warnDevices',
+    component: 'Input',
+    slot: 'monitor',
+  },
+  {
+    label: '配置控制设备',
+    field: 'controlDevices',
+    component: 'Select',
+    slot: 'controlDevices',
+  },
+  {
+    label: '分区数',
+    field: 'partNum',
+    component: 'Input',
+  },
+  {
+    label: '处理意见',
+    field: 'dealOpinion',
+    component: 'Input',
+    defaultValue: '立即检查该区域设备,启动应急预案。',
+  },
+  {
+    label: '所属系统',
+    field: 'systemType',
+    component: 'JDictSelectTag',
+    componentProps: { dictCode: 'kindtype' },
+  },
+];
+export const deviceFormColumns: FormSchema[] = [
+  {
+    label: '设备类型',
+    field: 'deviceType',
+    component: 'Select',
+  },
+  {
+    label: '点位',
+    field: 'monitorId',
+    component: 'Select',
+    slot: 'monitor',
+    required: true,
+  },
+  {
+    label: '报警上限值',
+    field: 'fmax',
+    component: 'InputNumber',
+  },
+  {
+    label: '报警下限值',
+    field: 'fmin',
+    component: 'InputNumber',
+  },
+  {
+    label: '报警持续时间(s)',
+    field: 'cxTime',
+    component: 'InputNumber',
+  },
+  {
+    label: '数据趋势',
+    field: 'dataTrend',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'dataTrend',
+      placeholder: '请选择数据趋势',
+    },
+  },
+  {
+    label: '数据趋势持续时间(h)',
+    field: 'trendCxTime',
+    component: 'InputNumber',
+  },
+];
+export const deviceControlColumns: FormSchema[] = [
+  {
+    label: '设备类型',
+    field: 'deviceType',
+    component: 'Select',
+  },
+  {
+    label: '点位',
+    field: 'monitorId',
+    component: 'Select',
+    slot: 'monitor',
+    required: true,
+  },
+  {
+    label: '值',
+    field: 'value',
+    component: 'Input',
+  },
+  {
+    label: '执行顺序',
+    field: 'orderNum',
+    component: 'InputNumber',
+  },
+  {
+    label: '操作描述',
+    field: 'remark',
+    component: 'Input',
+  },
+];
 export const manageWarningPointColumns: BasicColumn[] = [
   {
     title: '设备名称',

+ 250 - 238
src/views/vent/deviceManager/workingFace/CustomNormalTable.vue

@@ -31,280 +31,292 @@
       </template>
     </BasicTable>
     <DeviceModal @register="registerModal" @saveOrUpdate="saveOrUpdateHandler" :showTab="showTab" :deviceType="deviceType" />
-    <!-- <DeviceModal v-model:visible="modalVisible" @saveOrUpdate="saveOrUpdateHandler" @close-modal="closeModal" :showTab="showTab"  /> -->
+    <DeviceModalLeather @register="registerModalLeather" @saveOrUpdate="saveOrUpdateHandler" :showTab="showTab" :deviceType="deviceType" />
   </div>
 </template>
 
 <script lang="ts" setup>
-  //ts语法
-  import { ref, provide, reactive, toRaw, defineExpose, watch } from 'vue';
-  import { BasicTable, ActionItem, EditRecordRow, BasicColumn } from '/@/components/Table';
-  import { useModal } from '/@/components/Modal';
-  import DeviceModal from '../comment/DeviceModal.vue';
-  // import { getToken } from '/@/utils/auth';
-  // import { useGlobSetting } from '/@/hooks/setting';
-  import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
-  import { useListPage } from '/@/hooks/system/useListPage';
-  import { getPopupContainer } from '/@/utils';
-  import { message } from 'ant-design-vue';
+//ts语法
+import { ref, provide, reactive, toRaw, defineExpose, watch } from 'vue';
+import { BasicTable, ActionItem, EditRecordRow, BasicColumn } from '/@/components/Table';
+import { useModal } from '/@/components/Modal';
+import DeviceModal from '../comment/DeviceModal.vue';
+// import { getToken } from '/@/utils/auth';
+// import { useGlobSetting } from '/@/hooks/setting';
+import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
+import { useListPage } from '/@/hooks/system/useListPage';
+import { getPopupContainer } from '/@/utils';
+import { message } from 'ant-design-vue';
+import DeviceModalLeather from '../comment/DeviceModalLeather.vue';
 
-  const props = defineProps({
-    columnsType: {
-      type: String,
-      // required: true,
-    },
-    columns: {
-      type: Array,
-      // required: true,
-      default: () => [],
-    },
-    searchFormSchema: {
-      type: Array,
-      default: () => [],
-    },
-    formSchema: {
-      type: Array,
-      required: true,
-    },
-    list: {
-      type: Function,
-      required: true,
-    },
-    getImportUrl: {
-      type: String,
-    },
-    getExportUrl: {
-      type: String,
-    },
-    deleteById: {
-      type: Function,
-      required: true,
-    },
-    batchDelete: {
-      type: Function,
-    },
-    saveOrUpdate: {
-      type: Function,
-      required: true,
-    },
-    pointList: {
-      type: Function,
-    },
-    showTab: {
-      type: Boolean,
-      default: false,
-    },
-    designScope: {
-      type: String,
-    },
-    title: {
-      type: String,
-    },
-    deviceType: {
-      type: String,
-    },
-  });
+const props = defineProps({
+  columnsType: {
+    type: String,
+    // required: true,
+  },
+  columns: {
+    type: Array,
+    // required: true,
+    default: () => [],
+  },
+  searchFormSchema: {
+    type: Array,
+    default: () => [],
+  },
+  formSchema: {
+    type: Array,
+    required: true,
+  },
+  list: {
+    type: Function,
+    required: true,
+  },
+  getImportUrl: {
+    type: String,
+  },
+  getExportUrl: {
+    type: String,
+  },
+  deleteById: {
+    type: Function,
+    required: true,
+  },
+  batchDelete: {
+    type: Function,
+  },
+  saveOrUpdate: {
+    type: Function,
+    required: true,
+  },
+  pointList: {
+    type: Function,
+  },
+  showTab: {
+    type: Boolean,
+    default: false,
+  },
+  designScope: {
+    type: String,
+  },
+  title: {
+    type: String,
+  },
+  deviceType: {
+    type: String,
+  },
+});
 
-  const emit = defineEmits(['submitSuccess', 'editHandler']);
+const emit = defineEmits(['submitSuccess', 'editHandler']);
 
-  const isUpdate = ref(false);
-  const record = reactive({});
-  const formSchemaData = ref(props.formSchema);
-  const deviceTypeId = ref('');
-  const pageType = ref('');
+const isUpdate = ref(false);
+const record = reactive({});
+const formSchemaData = ref(props.formSchema);
+const deviceTypeId = ref('');
+const pageType = ref('');
 
-  watch(
-    () => props.formSchema,
-    (val) => {
-      formSchemaData.value = val;
-    }
-  );
-
-  provide('formSchema', formSchemaData);
-  provide('isUpdate', isUpdate);
-  provide('formData', record);
-  provide('deviceType', props.deviceType);
-  // const glob = useGlobSetting();
-  const [registerModal, { openModal, closeModal }] = useModal();
+watch(
+  () => props.formSchema,
+  (val) => {
+    formSchemaData.value = val;
+  }
+);
 
-  const columnList = getTableHeaderColumns(props.columnsType);
+provide('formSchema', formSchemaData);
+provide('isUpdate', isUpdate);
+provide('formData', record);
+provide('deviceType', props.deviceType);
+// const glob = useGlobSetting();
+const [registerModal, { openModal, closeModal }] = useModal();
+const [registerModalLeather, { openModal: openModalLeather, closeModal: closeModalLeather }] = useModal();
+const columnList = getTableHeaderColumns(props.columnsType);
 
-  // 列表页面公共参数、方法
-  const { prefixCls, tableContext, onExportXls, onImportXls, doRequest } = useListPage({
-    designScope: props.designScope,
-    tableProps: {
-      showTableSetting: false,
-      title: props.title,
-      api: props.list,
-      columns: props.columns.length > 0 ? (props.columns as any[]) : columnList,
-      // size: 'small',
-      // bordered: false,
-      showIndexColumn: true,
-      formConfig: {
-        showAdvancedButton: true,
-        // labelWidth: 100,
-        labelAlign: 'left',
-        labelCol: {
-          xs: 24,
-          sm: 24,
-          md: 24,
-          lg: 9,
-          xl: 7,
-          xxl: 5,
-        },
-        schemas: props.searchFormSchema as any[],
-      },
-      useSearchForm: props.searchFormSchema.length > 0 ? true : false,
-      striped: true,
-      actionColumn: {
-        width: 180,
-      },
-      beforeFetch: (params) => {
-        return Object.assign(params, { column: 'createTime', devicekind: props.deviceType });
+// 列表页面公共参数、方法
+const { prefixCls, tableContext, onExportXls, onImportXls, doRequest } = useListPage({
+  designScope: props.designScope,
+  tableProps: {
+    showTableSetting: false,
+    title: props.title,
+    api: props.list,
+    columns: props.columns.length > 0 ? (props.columns as any[]) : columnList,
+    // size: 'small',
+    // bordered: false,
+    showIndexColumn: true,
+    formConfig: {
+      showAdvancedButton: true,
+      // labelWidth: 100,
+      labelAlign: 'left',
+      labelCol: {
+        xs: 24,
+        sm: 24,
+        md: 24,
+        lg: 9,
+        xl: 7,
+        xxl: 5,
       },
+      schemas: props.searchFormSchema as any[],
+    },
+    useSearchForm: props.searchFormSchema.length > 0 ? true : false,
+    striped: true,
+    actionColumn: {
+      width: 180,
+    },
+    beforeFetch: (params) => {
+      return Object.assign(params, { column: 'createTime', devicekind: props.deviceType });
     },
-  });
+  },
+});
 
-  //注册table数据
-  const [registerTable, { reload, getForm }, { rowSelection, selectedRowKeys }] = tableContext;
+//注册table数据
+const [registerTable, { reload, getForm }, { rowSelection, selectedRowKeys }] = tableContext;
 
-  const saveOrUpdateHandler = async (params) => {
-    try {
-      await props.saveOrUpdate(params, isUpdate.value);
-      !props.showTab ? closeModal() : '';
-      await doRequest(props.list, { confirm: false });
-      emit('submitSuccess', params);
-    } catch (error) {
-      message.error('保存失败,请联系管理员');
-    }
-  };
+const saveOrUpdateHandler = async (params) => {
+  try {
+    await props.saveOrUpdate(params, isUpdate.value);
+    !props.showTab ? closeModal() : '';
+    await doRequest(props.list, { confirm: false });
+    emit('submitSuccess', params);
+  } catch (error) {
+    message.error('保存失败,请联系管理员');
+  }
+};
 
-  // const closeModalFn = () => {
-  //   closeModal()
-  // }
-  /**
-   * 新增事件
-   */
-  function handleAdd() {
-    const searchFormData = getForm().getFieldsValue();
-    if (searchFormData && searchFormData['strtype']) {
-      emit('editHandler', searchFormData);
-      for (let key in record) {
-        if (key == 'strtype') {
-          record[key] = searchFormData['strtype'];
-        } else {
-          delete record[key];
-        }
+// const closeModalFn = () => {
+//   closeModal()
+// }
+/**
+ * 新增事件
+ */
+function handleAdd() {
+  const searchFormData = getForm().getFieldsValue();
+  if (searchFormData && searchFormData['strtype']) {
+    emit('editHandler', searchFormData);
+    for (let key in record) {
+      if (key == 'strtype') {
+        record[key] = searchFormData['strtype'];
+      } else {
+        delete record[key];
       }
-      isUpdate.value = false;
-      openModal(
-        true,
-        {
-          record: { strtype: searchFormData['strtype'] },
-        },
-        false
-      );
-    } else {
-      message.info('请先选择系统类型!!');
     }
-  }
-
-  /**
-   * 编辑事件
-   */
-  function handleEdit(data) {
-    emit('editHandler', data);
-    isUpdate.value = true;
-    Object.assign(record, toRaw(data));
+    isUpdate.value = false;
     openModal(
       true,
       {
-        record,
+        record: { strtype: searchFormData['strtype'] },
       },
       false
     );
+  } else {
+    message.info('请先选择系统类型!!');
   }
+}
 
-  /**
-   * 删除事件
-   */
-  async function handleDelete(record) {
-    await props.deleteById({ id: record.id }, reload);
+/**
+ * 编辑事件
+ */
+// function handleEdit(data) {
+//   emit('editHandler', data);
+//   console.log(data, '----');
+//   isUpdate.value = true;
+//   Object.assign(record, toRaw(data));
+//   openModal(
+//     true,
+//     {
+//       record,
+//     },
+//     false
+//   );
+// }
+function handleEdit(data) {
+  emit('editHandler', data);
+  console.log(data, '----');
+  isUpdate.value = true;
+  Object.assign(record, toRaw(data));
+  if (data.strtype === 'sys_maintunnel_leather') {
+    openModalLeather(true, { record }, false);
+  } else {
+    openModal(true, { record }, false);
   }
+}
+/**
+ * 删除事件
+ */
+async function handleDelete(record) {
+  await props.deleteById({ id: record.id }, reload);
+}
 
-  /**
-   * 批量删除事件
-   */
-  async function batchHandleDelete() {
-    doRequest(() => props.batchDelete({ ids: selectedRowKeys.value }));
-  }
-  /**
-   * 查看
-   */
-  // function handleDetail(record) {
-  //   iframeUrl.value = `${glob.uploadUrl}/sys/annountCement/show/${record.id}?token=${getToken()}`;
-  //   openDetail(true);
-  // }
-  /**
-   * 操作列定义
-   * @param record
-   */
-  function getActions(record: EditRecordRow, column: BasicColumn): ActionItem[] {
-    return [
-      {
-        label: '编辑',
-        onClick: handleEdit.bind(null, record, column),
-      },
-      {
-        label: '删除',
-        popConfirm: {
-          title: '是否确认删除',
-          confirm: handleDelete.bind(null, record, column),
-        },
+/**
+ * 批量删除事件
+ */
+async function batchHandleDelete() {
+  doRequest(() => props.batchDelete({ ids: selectedRowKeys.value }));
+}
+/**
+ * 查看
+ */
+// function handleDetail(record) {
+//   iframeUrl.value = `${glob.uploadUrl}/sys/annountCement/show/${record.id}?token=${getToken()}`;
+//   openDetail(true);
+// }
+/**
+ * 操作列定义
+ * @param record
+ */
+function getActions(record: EditRecordRow, column: BasicColumn): ActionItem[] {
+  return [
+    {
+      label: '编辑',
+      onClick: handleEdit.bind(null, record, column),
+    },
+    {
+      label: '删除',
+      popConfirm: {
+        title: '是否确认删除',
+        confirm: handleDelete.bind(null, record, column),
       },
-      // {
-      //   label: '查看',
-      //   onClick: handleDetail.bind(null, record),
-      // },
-    ];
-  }
+    },
+    // {
+    //   label: '查看',
+    //   onClick: handleDetail.bind(null, record),
+    // },
+  ];
+}
 
-  defineExpose({
-    doRequest,
-    onExportXls,
-    onImportXls,
-    reload,
-    getForm,
-  });
+defineExpose({
+  doRequest,
+  onExportXls,
+  onImportXls,
+  reload,
+  getForm,
+});
 </script>
 
 <style scoped lang="less">
-  @ventSpace: zxm;
-  @vent-table-no-hover: #00bfff10;
+@ventSpace: zxm;
+@vent-table-no-hover: #00bfff10;
 
-  :deep(.@{ventSpace}-table-cell-row-hover) {
-    background: #264d8833 !important;
-  }
-  :deep(.@{ventSpace}-table-row-selected) {
-    background: #268bc522 !important;
-  }
+:deep(.@{ventSpace}-table-cell-row-hover) {
+  background: #264d8833 !important;
+}
+:deep(.@{ventSpace}-table-row-selected) {
+  background: #268bc522 !important;
+}
 
-  :deep(.@{ventSpace}-table-tbody > tr > td) {
-    background-color: #0dc3ff05;
+:deep(.@{ventSpace}-table-tbody > tr > td) {
+  background-color: #0dc3ff05;
+}
+:deep(.jeecg-basic-table-row__striped) {
+  td {
+    background-color: @vent-table-no-hover !important;
   }
-  :deep(.jeecg-basic-table-row__striped) {
-    td {
-      background-color: @vent-table-no-hover !important;
-    }
+}
+:deep(.@{ventSpace}-select-dropdown) {
+  .@{ventSpace}-select-item-option-selected,
+  .@{ventSpace}-select-item-option-active {
+    background-color: #ffffff33 !important;
   }
-  :deep(.@{ventSpace}-select-dropdown) {
-    .@{ventSpace}-select-item-option-selected,
-    .@{ventSpace}-select-item-option-active {
-      background-color: #ffffff33 !important;
-    }
 
-    .@{ventSpace}-select-item:hover {
-      background-color: #ffffff33 !important;
-    }
+  .@{ventSpace}-select-item:hover {
+    background-color: #ffffff33 !important;
   }
+}
 </style>

+ 135 - 0
src/views/vent/home/configurable/belt/components/detail/bottomMenu.vue

@@ -0,0 +1,135 @@
+<template>
+  <div class="bottom-btn-group">
+    <template v-if="buttonType != 'router'">
+      <div
+        v-for="item in navList"
+        :key="item.pathName"
+        class="vent-row-center btn-item"
+        :class="{ 'btn-item-active': isBtnActive === item.pathName || item.isHover }"
+        @click="setBtn('click', item)"
+      >
+        {{ item.title }}
+      </div>
+    </template>
+    <template v-else>
+      <div v-for="item in navList" :key="item.pathName" class="vent-row-center btn-item-route" @click="setBtn('click', item)">
+        {{ item.title }}
+      </div>
+    </template>
+  </div>
+</template>
+<script lang="ts">
+import { ref, defineComponent } from 'vue';
+type navListType = { title: string; pathName: string; isHover: Boolean };
+
+export default defineComponent({
+  name: 'BottomMenu',
+  props: {
+    navList: {
+      type: Array<navListType>,
+      default: () => [
+        {
+          title: '历史监测记录',
+          pathName: 'monitor_history',
+          isHover: false,
+        },
+        {
+          title: '操作历史记录',
+          pathName: 'handler_history',
+          isHover: false,
+        },
+        {
+          title: '故障诊断历史记录',
+          pathName: 'faultRecord',
+          isHover: false,
+        },
+      ],
+    },
+    type: {
+      type: String,
+      default: 'tab',
+    },
+  },
+  emits: ['change'],
+  setup(props, { emit }) {
+    const isBtnActive = ref(props.type !== 'router' ? props.navList[0].pathName : '');
+    const buttonType = props.type;
+    function setBtn(type, activeObj) {
+      if (type === 'click') {
+        isBtnActive.value = activeObj.pathName;
+        if (props.type !== 'router') activeObj.isHover = true;
+      }
+      props.navList.forEach((item) => {
+        if (item.title !== activeObj.title) {
+          if (props.type !== 'router') activeObj.isHover = false;
+        }
+      });
+      emit('change', isBtnActive.value);
+    }
+    return {
+      setBtn,
+      isBtnActive,
+      buttonType,
+    };
+  },
+});
+</script>
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+@{theme-deepblue} {
+  .bottom-btn-group {
+    --image-bottom-btn: url('/@/assets/images/themify/deepblue/vent/bottom-btn.png');
+    --image-bottom-btn-active: url('/@/assets/images/themify/deepblue/vent/bottom-btn-active.png');
+  }
+}
+
+.bottom-btn-group {
+  --image-bottom-btn: url('/@/assets/images/vent/bottom-btn.png');
+  --image-bottom-btn-active: url('/@/assets/images/vent/bottom-btn-active.png');
+  display: flex;
+  position: fixed;
+  width: 100%;
+  height: 100px;
+  bottom: 10px;
+  align-items: center;
+  justify-content: center;
+  pointer-events: auto;
+  z-index: 999;
+
+  .btn-item {
+    width: 182px;
+    height: 53px;
+    margin: 10px;
+    color: #fff;
+    cursor: pointer;
+    padding-bottom: 2px;
+    pointer-events: auto;
+    background: var(--image-bottom-btn);
+    font-family: 'ysbtFont';
+    font-size: 18px;
+  }
+  .btn-item-active {
+    background: var(--image-bottom-btn-active) !important;
+    color: #ffffff !important;
+  }
+  .btn-item-route {
+    width: 194px;
+    height: 73px;
+    margin: 10px;
+    color: #fff;
+    cursor: pointer;
+    padding-bottom: 2px;
+    pointer-events: auto;
+    font-weight: 600;
+    font-size: 16px;
+    background: url('/@/assets/images/vent/bottom-btn-route.png');
+    &:hover {
+      color: var(--vent-base-light-bg) !important;
+    }
+  }
+  .btn-item-route-active {
+    background: url('/@/assets/images/vent/bottom-btn-route-active.png') !important;
+  }
+}
+</style>

+ 15 - 6
src/views/vent/home/configurable/belt/components/detail/gateBoard.vue

@@ -17,8 +17,9 @@
             <div class="door-position">
               <div class="position"></div>
               <div class="door-name"
-                ><span>位置</span><span>{{ item.strname }}</span></div
+                ><span>{{ item.strname }}</span></div
               >
+              <a-button class="door-btn" @click="oneKeyClose(index)">一键双关</a-button>
               <a-button class="door-btn" @click="oneKeyOpen(index)">一键双开</a-button>
             </div>
             <div class="door-header">
@@ -93,21 +94,28 @@ function oneKeyOpen(index) {
     childRefs.value[index].animate(true, true, true);
   }
 }
+function oneKeyClose(index) {
+  if (childRefs.value[index]) {
+    // 直接强制两个都打开!
+    childRefs.value[index].animate(false, false, false);
+  }
+}
 
 watch(
   () => props.data,
   (newData) => {
-    const values = Object.values(newData ?? {});
-    const allItems = values.flat();
-    allItems.forEach((item, index) => {
+    if (!newData || !newData.length) return;
+    // 遍历每一项,执行动画(初始化 + 数据更新都生效)
+    newData.forEach((item, index) => {
       monitorAnimation(item, index);
     });
   },
   {
     deep: true,
-    immediate: true,
+    immediate: true, // 初始化立刻执行
   }
 );
+onMounted(() => {});
 </script>
 
 <style scoped lang="less">
@@ -216,7 +224,7 @@ watch(
   display: flex;
   flex-direction: row;
   justify-content: space-between;
-  font-size: 14px;
+  font-size: 12px;
   font-weight: bold;
   color: #c4ebff;
   margin: 0 25px 0 25px;
@@ -231,6 +239,7 @@ watch(
   padding: 2px 8px;
   height: 24px;
   margin: auto;
+  margin-left: 3px;
   box-shadow: 0 0 6px 2px rgba(24, 144, 255, 0.4);
   display: inline-flex;
   align-items: center;

+ 90 - 0
src/views/vent/home/configurable/belt/components/detail/history.vue

@@ -0,0 +1,90 @@
+<template>
+  <div class="scene-box">
+    <div class="center-container">
+      <div class="history-group">
+        <div class="history-container">
+          <workFaceHistory
+            v-if="activeKey == 'monitor_history' && isRefresh"
+            ref="historyTable"
+            class="vent-margin-t-20"
+            :deviceId="optionValue"
+            :device-type="deviceType"
+          />
+          <!-- <workFaceHandleHistory
+            v-if="activeKey == 'handler_history' && isRefresh"
+            ref="alarmHistoryTable"
+            class="vent-margin-t-20"
+            :deviceId="optionValue"
+            :device-type="deviceType"
+          />
+          <workFaceAlarmHistory
+            v-if="activeKey == 'faultRecord' && isRefresh"
+            ref="handlerHistoryTable"
+            class="vent-margin-t-20"
+            :deviceId="optionValue"
+            :device-type="deviceType"
+          /> -->
+        </div>
+      </div>
+    </div>
+    <BottomMenu @change="changeActive" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onBeforeMount, ref, onMounted, onUnmounted, nextTick } from 'vue';
+import BottomMenu from './bottomMenu.vue';
+import workFaceHistory from './workFaceHistory.vue';
+
+type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
+const deviceList = ref<DeviceType[]>([]);
+const activeKey = ref('monitor_history');
+const deviceActive = ref('');
+const deviceType = ref('');
+const optionValue = ref('');
+const loading = ref(false);
+const isRefresh = ref(true);
+function changeActive(activeValue) {
+  activeKey.value = activeValue;
+  loading.value = true;
+}
+</script>
+<style lang="less" scoped>
+@import '/@/design/vent/modal.less';
+@import '/@/design/theme.less';
+@ventSpace: zxm;
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  overflow: auto;
+}
+.scene-box {
+  --image-wokeFaca-nav: url('/@/assets/images/vent/wokeFaca-nav.png');
+  --gradient-0: linear-gradient(45deg, #96c5ca38, #156c7d4a);
+  --color-0: #73e8fe;
+  --color-2: #96c5ca38;
+  --color-3: #156c7d4a;
+  --color-5: #0d2b46;
+  --color-6: #00fffd22;
+  --color-7: #44b4ff33;
+  --color-10: #6176af;
+  --color-15: #ffffff88;
+  --color-16: #f73b2440;
+  --color-18: #ff9b1740;
+  --color-22: #ffa500;
+  width: 100%;
+  height: 100%;
+}
+.history-group {
+  padding: 0 30px;
+  margin-top: 90px;
+  .history-container {
+    position: relative;
+    background: var(--color-5);
+    width: calc(100% + 10px);
+    left: -10px;
+    border: 1px solid var(--color-6);
+    padding: 10px 0;
+    box-shadow: 0 0 20px var(--color-7) inset;
+  }
+}
+</style>

+ 25 - 0
src/views/vent/home/configurable/belt/components/detail/workFaceHistory.vue

@@ -0,0 +1,25 @@
+<template>
+  <div class="history-box">
+    <HistoryTable :device-code="`${deviceType}`" :dict-code="`${deviceType}_dict`" :scroll="{ y: 650 }" />
+  </div>
+</template>
+<script setup lang="ts">
+import { ref, defineProps } from 'vue';
+// import HistoryTable from '../../comment/HistoryTable.vue';
+import HistoryTable from '/@/views/vent/comment/history/HistoryTable.vue';
+const props = defineProps({
+  deviceType: {
+    type: String,
+    required: true,
+  },
+  deviceId: {
+    type: String,
+    required: true,
+  },
+});
+</script>
+<style lang="less" scoped>
+.history-box {
+  pointer-events: auto;
+}
+</style>

+ 2 - 0
src/views/vent/home/configurable/belt/configurable.api.ts

@@ -7,9 +7,11 @@ import _ from 'lodash';
 
 enum Api {
   getSystem = '/modelreq/monitor/system',
+  getDevice = '/modelreq/monitor/device',
 }
 
 export const getSystem = (params) => defHttp.post({ url: Api.getSystem, params });
+export const getDevice = (params) => defHttp.post({ url: Api.getDevice, params });
 
 // 搞这个缓存是由于:目前代码上的设计是多个模块发出多次请求,每个模块自己负责消费前者的响应。
 // 这会导致相同的请求被同时发送多次。

+ 21 - 7
src/views/vent/home/configurable/belt/configurable.data.ts

@@ -59,7 +59,7 @@ export const testBeltLaneFire: Config[] = [
         },
       ],
       preset: [],
-      to: '/belt/fireS?pageType=fireMonitor',
+      to: '/belt/fireS/home?pageType=fireMonitor',
     },
     showStyle: {
       size: 'width:430px;height:350px;',
@@ -125,7 +125,7 @@ export const testBeltLaneFire: Config[] = [
         },
       ],
       preset: [],
-      to: '/belt/fireS?pageType=fireMonitor',
+      to: '/belt/fireS/home?pageType=fireMonitor',
     },
     showStyle: {
       size: 'width:430px;height:430px;',
@@ -216,7 +216,7 @@ export const testBeltLaneFire: Config[] = [
           readFrom: '',
         },
       ],
-      to: '/belt/fireS?pageType=sprayControl',
+      to: '/belt/fireS/home?pageType=sprayControl',
     },
     showStyle: {
       size: 'width:430px;height:350px;',
@@ -287,7 +287,7 @@ export const testBeltLaneFire: Config[] = [
       list: [],
       complex_list: [],
       preset: [],
-      to: '/belt/fireS?pageType=emergencyControl',
+      to: '/belt/fireS/home?pageType=emergencyControl',
     },
     showStyle: {
       size: 'width:430px;height:430px;',
@@ -1167,7 +1167,7 @@ export const testSpary: Config[] = [
         },
       },
       background: {
-        show: true,
+        show: false,
         type: 'video',
         link: '',
       },
@@ -1175,7 +1175,7 @@ export const testSpary: Config[] = [
         direction: 'row',
         items: [
           {
-            name: 'list',
+            name: 'CameraListTest',
             basis: '100%',
           },
         ],
@@ -1187,7 +1187,21 @@ export const testSpary: Config[] = [
       table: [],
       list: [],
       complex_list: [],
-      preset: [],
+      preset: [
+        {
+          readFrom: 'deviceInfo.gate.datalist',
+          config: {
+            title: 'name',
+            contents: [
+              {
+                code: '',
+                value: '',
+                info: '',
+              },
+            ],
+          },
+        },
+      ],
       // mock: BDfireMock,
     },
     showStyle: {

+ 15 - 3
src/views/vent/home/configurable/components/belt/CameraList.vue

@@ -8,8 +8,7 @@
 </template>
 
 <script setup lang="ts">
-import { onMounted, ref, onBeforeUnmount } from 'vue';
-// 用你成熟的摄像头hooks
+import { onMounted, nextTick, watch, ref, onBeforeUnmount } from 'vue';
 import { useCamera } from '/@/hooks/system/useCameraPianation';
 
 const props = defineProps({
@@ -38,9 +37,22 @@ const allCameras = () => {
   });
   return list;
 };
-onMounted(async () => {
+const loadCameras = async () => {
+  await nextTick();
   const cameras = allCameras();
+  if (cameras.length === 0) return;
+  removeCamera(playerRef);
   await getCamera('', playerRef, renderPlayer, '', cameras);
+};
+watch(
+  () => props.data,
+  () => {
+    loadCameras();
+  },
+  { deep: true, immediate: true }
+);
+onMounted(() => {
+  loadCameras();
 });
 
 // 销毁

+ 70 - 0
src/views/vent/home/configurable/components/belt/CameraListTest.vue

@@ -0,0 +1,70 @@
+<template>
+  <div class="camera-modal">
+    <div class="camera-area">
+      <div v-for="item in videoList" :key="item.id" class="video-item">
+        <video class="live-video" muted loop autoplay playsinline>
+          <source :src="item.url" type="video/mp4" />
+        </video>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+const props = defineProps({
+  data: {
+    type: Array,
+    default: () => [],
+  },
+});
+
+const videoList = ref([
+  {
+    id: 1,
+    url: '/sparyVideo.mp4',
+  },
+  {
+    id: 2,
+    url: '/sparyVideo.mp4',
+  },
+  {
+    id: 3,
+    url: '/sparyVideo.mp4',
+  },
+]);
+</script>
+
+<style lang="less" scoped>
+.camera-modal {
+  width: 100%;
+  height: 100%;
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+.camera-area {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 16px; // 视频间距
+  justify-content: flex-start;
+}
+
+// 视频项样式
+.video-item {
+  width: 395px;
+  height: 240px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  background: url('/@/assets/images/vent/camera_bg.png');
+  background-size: 100% 100%;
+  .live-video {
+    width: 90%;
+    height: 86%;
+    margin-top: 15px;
+  }
+}
+</style>

+ 4 - 0
src/views/vent/home/configurable/components/content.vue

@@ -204,6 +204,9 @@
         <template v-if="config.name === 'cameraList'">
           <CameraList class="content__module" :config="config.config" :data="config.data" />
         </template>
+        <template v-if="config.name === 'CameraListTest'">
+          <CameraListTest class="content__module" :config="config.config" :data="config.data" />
+        </template>
         <!-- <template v-if="config.key === 'fire_control'">
         <FIreControl class="content__module" />
       </template>
@@ -277,6 +280,7 @@ import ComplexList1Belt from './belt/ComplexList1Belt.vue';
 import CustomTableBelt from './belt/CustomTableBelt.vue';
 import SprayControl from './belt/SprayControl.vue';
 import CameraList from './belt/CameraList.vue';
+import CameraListTest from './belt/CameraListTest.vue';
 const props = defineProps<{
   data: any;
   moduleData: Config['moduleData'];