From 97dc174b26461df1395394c02401bb51dd6376bc Mon Sep 17 00:00:00 2001
From: bsw215583320 <baoshiwei121@163.com>
Date: 星期一, 04 十二月 2023 08:03:53 +0800
Subject: [PATCH] 增加opc设备维护和控制功能

---
 src/views/dashboard/control/api.ts             |   14 
 src/views/dry/components/DryOpcDeviceModal.vue |   66 ++++
 src/views/dry/DryOpcDeviceList.vue             |  174 +++++++++++
 src/assets/images/dry/control/light.png        |    0 
 src/assets/images/dry/control/cam0.png         |    0 
 src/views/dashboard/control/index.vue          |  296 +++++++++++++++++++
 src/views/dry/sql/DryOpcDevice_menu_insert.sql |   26 +
 src/assets/images/dry/control/light-close.png  |    0 
 src/views/dry/api/DryOpcDevice.api.ts          |   64 ++++
 src/views/dry/components/DryOpcDeviceForm.vue  |   70 ++++
 src/views/dry/dataDefine/DryOpcDevice.data.ts  |  109 +++++++
 src/assets/images/dry/control/cam1.png         |    0 
 src/views/dry/bigScreen/BigWorkShop.vue        |   51 ++
 src/assets/images/dry/control/cam.png          |    0 
 src/assets/images/dry/control/cam-close.png    |    0 
 15 files changed, 850 insertions(+), 20 deletions(-)

diff --git a/src/assets/images/dry/control/cam-close.png b/src/assets/images/dry/control/cam-close.png
new file mode 100644
index 0000000..0218b87
--- /dev/null
+++ b/src/assets/images/dry/control/cam-close.png
Binary files differ
diff --git a/src/assets/images/dry/control/cam.png b/src/assets/images/dry/control/cam.png
new file mode 100644
index 0000000..bb963f1
--- /dev/null
+++ b/src/assets/images/dry/control/cam.png
Binary files differ
diff --git a/src/assets/images/dry/control/cam0.png b/src/assets/images/dry/control/cam0.png
new file mode 100644
index 0000000..1f285b9
--- /dev/null
+++ b/src/assets/images/dry/control/cam0.png
Binary files differ
diff --git a/src/assets/images/dry/control/cam1.png b/src/assets/images/dry/control/cam1.png
new file mode 100644
index 0000000..c3a2695
--- /dev/null
+++ b/src/assets/images/dry/control/cam1.png
Binary files differ
diff --git a/src/assets/images/dry/control/light-close.png b/src/assets/images/dry/control/light-close.png
new file mode 100644
index 0000000..9c64966
--- /dev/null
+++ b/src/assets/images/dry/control/light-close.png
Binary files differ
diff --git a/src/assets/images/dry/control/light.png b/src/assets/images/dry/control/light.png
new file mode 100644
index 0000000..057ead2
--- /dev/null
+++ b/src/assets/images/dry/control/light.png
Binary files differ
diff --git a/src/views/dashboard/control/api.ts b/src/views/dashboard/control/api.ts
index 76a5c9f..703be84 100644
--- a/src/views/dashboard/control/api.ts
+++ b/src/views/dashboard/control/api.ts
@@ -2,6 +2,8 @@
 
 enum Api {
   sendCommand = '/dry/real/sendCommand',
+  sendWriteCommand = '/dry/opc/sendWriteCommand',
+  listAll = '/dry/dryOpcDevice/listAll'
 }
 /**
  * 鍙戦�佸懡浠�
@@ -9,3 +11,15 @@
  */
 export const sendCommand = (params) => defHttp.post({ url: Api.sendCommand, params },{ isTransformResponse: false });
 
+/**
+ * 鍙戦�丱PC鍐欐寚浠�
+ */
+
+export const sendWriteCommand = (params) => defHttp.post({url: Api.sendWriteCommand, params},{isTransformResponse: false})
+
+/**
+ * 鏌ヨ鎵�鏈塐PC璁惧
+ */
+
+export const listAll = (params) => defHttp.get({url:Api.listAll, params})
+
diff --git a/src/views/dashboard/control/index.vue b/src/views/dashboard/control/index.vue
index 5085e12..e9d321d 100644
--- a/src/views/dashboard/control/index.vue
+++ b/src/views/dashboard/control/index.vue
@@ -7,12 +7,125 @@
 
   </a-modal>
   <div class="app">
-    <a-card title="鎸囦护">
+    <a-row>
+      <a-card title="鐓ф槑" style="width: 60%">
+      <div class="light-box">
+        <div v-for="item in lightList" :key="item.identifier"  class="center">
+          <!-- <a-button v-if="item.type == 0"  type="primary" class="com-btn"
+                  @click="deviceClick(item)">
+          {{ item.name }}
+        </a-button> -->
+          <div v-if="item.type==0" @click="deviceClick(item)">
+            <div   :class="[ item.value?'lightOn':'lightOff' ,'device']">
+
+              
+            </div>
+            <div class="text-center">{{ item.name }}</div>
+              
+            </div>
+        </div>
+       
+      </div>
+    </a-card>
+    <a-card title="鐩戞帶" style="width: 35%; margin-left: 10px;">
+      <div class="monitor-box">
+        <div v-for="item in lightList" :key="item.identifier" class="center" >
+          <div v-if="item.type==1" @click="deviceClick(item)">
+            <div   :class="[ item.value?'camOn':'camOff' ,'device']">
+
+              
+            </div>
+            <div class="text-center">{{ item.name }}</div>
+            </div>
+      </div>
+      </div>
+    </a-card>
+
+    </a-row>
+    
+    <a-card title="鎸囦护" style="margin-top: 10px">
       <div class="com-box">
-        <a-button v-for="item in comList" :key="item.id" type="primary" class="com-btn"
+        <!-- <a-button v-for="item in comList" :key="item.id" type="primary" class="com-btn"
                   @click="comClick(item)">
           {{ item.title }}
+        </a-button> -->
+        <div style="width: 500px;">
+        
+        <a-row class="button-row">
+          <a-button type="primary" @click="clickButton(1010, '骞茬嚗鍚姩')" class="com-btn">  
+            <div> <PlayCircleOutlined style="font-size: 20px;" /> </div>
+          <div>  骞茬嚗鍚姩 </div>
+          
         </a-button>
+        <!-- <a-button type="normal" @click="clickButton(1012)" class="com-btn">
+          <div> <SplitCellsOutlined style="font-size: 20px;" /> </div>
+          <div>  鍚庨棬寮�鍏� </div>
+          
+        </a-button> -->
+        <a-button type="default" @click="clickButton(1003,'婊氱瓛鍗�')" class="com-btn w300">
+          <div> <UpCircleOutlined style="font-size: 20px;" /> </div>
+          <div>  婊氱瓛鍗� </div>
+          
+        </a-button>
+        <a-button type="info" @click="clickButton(1014, '寮�闂ㄨ瀵�')" class="com-btn">
+          <div> <SettingOutlined style="font-size: 20px;" /> </div>
+          <div>  寮�闂ㄨ瀵� </div>
+          
+        </a-button>
+        </a-row>
+        <a-row class="button-row">
+          <a-button type="normal" @click="clickButton(1005,'婊氱瓛姝h浆')" class="com-btn h100">
+            <div>  <RedoOutlined style="font-size: 20px;" /> </div>
+            <div> 婊氱瓛姝h浆 </div>
+        </a-button>
+          <a-button type="danger" @click="clickButton(1007,'鍋滄')" class="com-btn h100 w300 " >
+            <div> <PauseCircleOutlined style="font-size: 20px;" />  </div>
+            <div>  鍋滄 </div>
+        </a-button>
+        <a-button type="normal" @click="clickButton(1006,'婊氱瓛鍙嶈浆')" class="com-btn h100">
+          <div> <UndoOutlined style="font-size: 20px;" /> </div>
+          <div>  婊氱瓛鍙嶈浆 </div>
+        </a-button>
+        </a-row>
+        <a-row class="button-row">
+          <a-button type="success" @click="clickButton(1015,'鍑烘枡')" class="com-btn">
+            <div> <DownloadOutlined style="font-size: 20px;" /> </div>
+            <div>  鍑烘枡 </div>
+          
+        </a-button>
+        <!-- <a-button type="normal" @click="clickButton(1010)" class="com-btn">
+          <div> <SplitCellsOutlined style="font-size: 20px;" /> </div>
+          <div>  鍓嶉棬寮�鍏� </div>
+        </a-button> -->
+        <a-button type="normal" @click="clickButton(1004,'婊氱瓛闄�')" class="com-btn w300">
+          <div> <DownCircleOutlined style="font-size: 20px;" /> </div>
+          <div>  婊氱瓛闄� </div>
+        </a-button>
+        <a-button type="normal" @click="clickButton(1013,'鐑鍚姩')" class="com-btn">
+          <div> <FireOutlined style="font-size: 20px;" /> </div>
+            <div>  鐑鍚姩 </div>
+          
+        </a-button>
+      </a-row>
+       
+        </div>
+        <div style="margin-left: 100px;">
+          <div>
+          <a-button type="warning" @click="clickButton(1017,'鎵嬪姩/鑷姩')" class="com-btn">
+            <div> <SyncOutlined style="font-size: 20px;" /> </div>
+          <div>  鎵嬪姩/鑷姩 </div>
+          
+        </a-button>
+      </div>
+      <div>
+        <a-button type="normal" @click="clickButton(1016,'娓呴櫎')" class="com-btn">
+          <div> <ClearOutlined style="font-size: 20px;" /> </div>
+          <div>  娓呴櫎 </div>
+          
+        </a-button>
+      </div>
+        </div>
+
       </div>
     </a-card>
     <a-card title="鎺у埗鍙�" style="margin-top: 10px">
@@ -26,16 +139,28 @@
 
 <script setup lang="ts">
 import { ref, onMounted } from "vue";
-import { sendCommand } from "./api";
+import { sendCommand, sendWriteCommand, listAll } from "./api";
+import { useGlobSetting } from '/@/hooks/setting';
+import { connectWebSocket, onWebSocket } from '/@/hooks/web/useWebSocket';
+import { useUserStore } from '/@/store/modules/user';
+import { RedoOutlined ,SettingOutlined, UndoOutlined,FireOutlined, SplitCellsOutlined, DownloadOutlined, PauseCircleOutlined,ClearOutlined, SyncOutlined,PlayCircleOutlined, SwapOutlined , UpCircleOutlined, DownCircleOutlined, LeftCircleOutlined, RightCircleOutlined} from '@ant-design/icons-vue';
+
 
 const visible = ref<boolean>(false);
-
+  const glob = useGlobSetting();
 interface Commant {
   id: number;
   title: string;
   icon: string;
 }
 
+interface Device {
+  name: string;
+  identifier: string;
+  value: boolean;
+  sort_order: number;
+}
+const userStore = useUserStore();
 const logList = ref<string[]>([]);
 const comList = ref<Commant[]>([
   {
@@ -88,6 +213,9 @@
     icon: "caret-right-outlined"
   }]);
 
+
+const lightList = ref<Device[]>([]);
+const monitorList = ref<Device[]>([]);
 function comClick(item) {
   addLog("鍙戦��", item.title);
   //鍙戦�佹寚浠�
@@ -133,9 +261,81 @@
   visible.value = false;
 };
 
+/**
+ * 鏌ヨ鐏拰鎽勫儚澶村垪琛�
+ */
+function queryDevice() {
+  listAll({}).then(res => {
+    console.log("ress000:",res);
+    lightList.value = res
+  })
+
+
+}
+
+function clickButton(cmd, msg) {
+  console.log("target::::",cmd);
+  var params = { msg: msg, code: cmd, tenantId: 1003, machineId: "GM001" };
+  sendCommand(params).then(res => {
+    if (res.success) {
+      addLog("鍝嶅簲", res.message);
+      console.info(res);
+    } else {
+      console.info(res);
+      addLog("鍝嶅簲", res.message);
+    }
+
+  });
+}
+
+
+
+
+function deviceClick(item) {
+  //console.log("item===",item.value);
+  let params = {code: item.identifier, msg: !item.value}
+  sendWriteCommand(params).then(res => {
+    console.log("鍐欐寚浠ょ粨鏋滐細锛�", res)
+    if(res.success) {
+      lightList.value.forEach(device => {
+          if(device.identifier == item.identifier) {
+            device.value = !item.value
+          }
+        })
+    }
+  }) 
+
+}
+
+    // 鍒濆鍖� WebSocket
+    function initWebSocket() {
+
+        let user = userStore.getUserInfo;
+        let tenantId = user.loginTenantId;
+
+        console.log(user);
+        // WebSocket涓庢櫘閫氱殑璇锋眰鎵�鐢ㄥ崗璁湁鎵�涓嶅悓锛寃s绛夊悓浜巋ttp锛寃ss绛夊悓浜巋ttps
+         let url = glob.domainUrl?.replace('https://', 'wss://').replace('http://', 'ws://') + '/drySocket/' + tenantId;
+        
+         connectWebSocket(url);
+         onWebSocket(onWebSocketMessage);
+      }
+
+      function onWebSocketMessage(data) {
+        console.log("drysocket:data::",data)
+        lightList.value.forEach(item => {
+          if(item.identifier == data.identifier) {
+            item.value = data.value
+          }
+        })
+      }
+
 onMounted(() => {
   showModal();
+  initWebSocket();
 });
+
+queryDevice()
 
 
 </script>
@@ -146,23 +346,101 @@
 }
 
 .com-box {
-  display: flex;
-  flex-wrap: wrap;
+  // margin-left: 200px;
 
+  display: flex;
+
+  
   .com-btn {
+    border-radius: 5px;
+    width: 100px;
     margin: 10px;
+    height: 70px;
   }
 }
 
+.button-row {
+  display: flex; justify-content: space-between;
+}
+
 .log-box {
-  min-height: 200px;
-  max-height: 300px;
-  overflow-y: scroll;
+  min-height: 150px;
+  max-height: 150px;
+  overflow-y: auto;
 }
 .indented-text {
   text-indent: 20px;
   font-size: 16px;
 }
 
+.light-box {
+  display: flex;
+  justify-items: center;
+justify-content: center;
+  flex-wrap: wrap;
+
+}
+.center {
+  display: flex;
+justify-items: center;
+justify-content: center;
+}
+
+.text-center {
+  text-align: center;
+}
+
+.lightOn {
+    background-image: url(/src/assets/images/dry/control/light.png);
+    background-repeat: no-repeat;
+		background-size: 50px;
+		/* border-radius: 10px; */
+		background-position: 48px 0px;
+  }
+  .lightOff {
+    background-image: url(/src/assets/images/dry/control/light-close.png);
+    background-repeat: no-repeat;
+		background-size: 50px;
+		/* border-radius: 10px; */
+		background-position: 48px 0px;
+  }
+
+  .camOn {
+    background-image: url(/src/assets/images/dry/control/cam1.png);
+    background-repeat: no-repeat;
+		background-size: 50px;
+		/* border-radius: 10px; */
+		background-position: 48px 0px;
+  }
+  .camOff {
+    background-image: url(/src/assets/images/dry/control/cam0.png);
+    background-repeat: no-repeat;
+		background-size: 50px;
+		/* border-radius: 10px; */
+		background-position: 48px 0px;
+  }
+
+
+.device {
+  width: 150px; height: 60px; 
+  
+}
+
+.h100 {
+  height: 70px !important;
+}
+
+.w300 {
+  width: 100px !important;
+}
+
+.monitor-box {
+  display: flex;
+  justify-items: center;
+justify-content: center;
+flex-wrap: wrap;
+  
+}
+
 
 </style>
diff --git a/src/views/dry/DryOpcDeviceList.vue b/src/views/dry/DryOpcDeviceList.vue
new file mode 100644
index 0000000..f0b4892
--- /dev/null
+++ b/src/views/dry/DryOpcDeviceList.vue
@@ -0,0 +1,174 @@
+<template>
+  <div>
+    <!--寮曠敤琛ㄦ牸-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--鎻掓Ы:table鏍囬-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 鏂板</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 瀵煎嚭</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">瀵煎叆</j-upload-button>
+          <a-dropdown v-if="selectedRowKeys.length > 0">
+              <template #overlay>
+                <a-menu>
+                  <a-menu-item key="1" @click="batchHandleDelete">
+                    <Icon icon="ant-design:delete-outlined"></Icon>
+                    鍒犻櫎
+                  </a-menu-item>
+                </a-menu>
+              </template>
+              <a-button>鎵归噺鎿嶄綔
+                <Icon icon="mdi:chevron-down"></Icon>
+              </a-button>
+        </a-dropdown>
+      </template>
+       <!--鎿嶄綔鏍�-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+      <!--瀛楁鍥炴樉鎻掓Ы-->
+      <template #htmlSlot="{text}">
+         <div v-html="text"></div>
+      </template>
+      <!--鐪佸競鍖哄瓧娈靛洖鏄炬彃妲�-->
+      <template #pcaSlot="{text}">
+         {{ getAreaTextByCode(text) }}
+      </template>
+      <template #fileSlot="{text}">
+         <span v-if="!text" style="font-size: 12px;font-style: italic;">鏃犳枃浠�</span>
+         <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">涓嬭浇</a-button>
+      </template>
+    </BasicTable>
+    <!-- 琛ㄥ崟鍖哄煙 -->
+    <DryOpcDeviceModal @register="registerModal" @success="handleSuccess"></DryOpcDeviceModal>
+  </div>
+</template>
+
+<script lang="ts" name="dry-dryOpcDevice" setup>
+  import {ref, computed, unref} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import {useModal} from '/@/components/Modal';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import DryOpcDeviceModal from './components/DryOpcDeviceModal.vue'
+  import {columns, searchFormSchema} from './dataDefine/DryOpcDevice.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './api/DryOpcDevice.api';
+  import { downloadFile } from '/@/utils/common/renderUtils';
+  const checkedKeys = ref<Array<string | number>>([]);
+  //娉ㄥ唽model
+  const [registerModal, {openModal}] = useModal();
+  //娉ㄥ唽table鏁版嵁
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+      tableProps:{
+           title: 'dry_opc_device',
+           api: list,
+           columns,
+           canResize:false,
+           formConfig: {
+              //labelWidth: 120,
+              schemas: searchFormSchema,
+              autoSubmitOnEnter:true,
+              showAdvancedButton:true,
+              fieldMapToNumber: [
+              ],
+              fieldMapToTime: [
+              ],
+            },
+           actionColumn: {
+               width: 120,
+               fixed:'right'
+            },
+      },
+       exportConfig: {
+            name:"dry_opc_device",
+            url: getExportUrl,
+          },
+          importConfig: {
+            url: getImportUrl,
+            success: handleSuccess
+          },
+  })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+   /**
+    * 鏂板浜嬩欢
+    */
+  function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+  }
+   /**
+    * 缂栬緫浜嬩欢
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 璇︽儏
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 鍒犻櫎浜嬩欢
+    */
+  async function handleDelete(record) {
+    console.log(record);
+     await deleteOne({id: record.id}, handleSuccess);
+   }
+   /**
+    * 鎵归噺鍒犻櫎浜嬩欢
+    */
+  async function batchHandleDelete() {
+     await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
+   }
+   /**
+    * 鎴愬姛鍥炶皟
+    */
+  function handleSuccess() {
+      (selectedRowKeys.value = []) && reload();
+   }
+   /**
+      * 鎿嶄綔鏍�
+      */
+  function getTableAction(record){
+       return [
+         {
+           label: '缂栬緫',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+   }
+     /**
+        * 涓嬫媺鎿嶄綔鏍�
+        */
+  function getDropDownAction(record){
+       return [
+         {
+           label: '璇︽儏',
+           onClick: handleDetail.bind(null, record),
+         }, {
+           label: '鍒犻櫎',
+           popConfirm: {
+             title: '鏄惁纭鍒犻櫎',
+             confirm: handleDelete.bind(null, record),
+           }
+         }
+       ]
+   }
+
+
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dry/api/DryOpcDevice.api.ts b/src/views/dry/api/DryOpcDevice.api.ts
new file mode 100644
index 0000000..21ed673
--- /dev/null
+++ b/src/views/dry/api/DryOpcDevice.api.ts
@@ -0,0 +1,64 @@
+import {defHttp} from '/@/utils/http/axios';
+import { useMessage } from "/@/hooks/web/useMessage";
+
+const { createConfirm } = useMessage();
+
+enum Api {
+  list = '/dry/dryOpcDevice/list',
+  save='/dry/dryOpcDevice/add',
+  edit='/dry/dryOpcDevice/edit',
+  deleteOne = '/dry/dryOpcDevice/delete',
+  deleteBatch = '/dry/dryOpcDevice/deleteBatch',
+  importExcel = '/dry/dryOpcDevice/importExcel',
+  exportXls = '/dry/dryOpcDevice/exportXls',
+}
+/**
+ * 瀵煎嚭api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+/**
+ * 瀵煎叆api
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 鍒楄〃鎺ュ彛
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 鍒犻櫎鍗曚釜
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 鎵归噺鍒犻櫎
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  createConfirm({
+    iconType: 'warning',
+    title: '纭鍒犻櫎',
+    content: '鏄惁鍒犻櫎閫変腑鏁版嵁',
+    okText: '纭',
+    cancelText: '鍙栨秷',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 淇濆瓨鎴栬�呮洿鏂�
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
diff --git a/src/views/dry/bigScreen/BigWorkShop.vue b/src/views/dry/bigScreen/BigWorkShop.vue
index 9c9db95..c5c59a1 100644
--- a/src/views/dry/bigScreen/BigWorkShop.vue
+++ b/src/views/dry/bigScreen/BigWorkShop.vue
@@ -19,12 +19,12 @@
 						<div style="display: flex; width: 120px">
 							<Icon style="color: #ba9853" icon="mdi:home-temperature-outline" :size="28" />
 							&nbsp;
-							<div style="font-size: 20px; line-height: 26px"> 26 鈩� </div>
+							<div style="font-size: 20px; line-height: 26px"> {{envTemp}} 鈩� </div>
 						</div>
 						<div style="display: flex">
 							<Icon style="color: #ba9853" icon="wi:humidity" :size="28" />
 							&nbsp;
-							<div style="font-size: 20px; line-height: 26px"> 53 %rh </div>
+							<div style="font-size: 20px; line-height: 26px"> {{envHum}} %rh </div>
 						</div>
 					</div>
 					<div class="feed">
@@ -58,7 +58,7 @@
 											鐢甸噺娑堣��
 										</div>
 										<div class="stat_value">
-											462 
+											{{dianneng.toFixed(2)}} 
 											<span class="font16">
 												Kwh
 										</span>
@@ -79,7 +79,7 @@
 											钂告苯娑堣��
 										</div>
 										<div class="stat_value">
-											683 
+											{{zhengqi.toFixed(2)}} 
 											<span class="font16">
 												m鲁
 										</span>
@@ -285,6 +285,7 @@
 							</div>
 						</div>
 					</div>
+
 					<div class="footer">
 						
 						<div >{{ nowDate }}</div> 
@@ -311,6 +312,13 @@
 	const eqps = ref([] as dryEquipment[])
 	const title = ref("鍏版郸鏅鸿兘骞茬嚗杞﹂棿")
 	const userStore = useUserStore()
+	const envHum = ref();
+	const envTemp = ref();
+	const zhengqi = ref();
+	const dianneng = ref()
+
+	const steam = ref();
+	const watt = ref()
 	console.log(userStore.dictItems.title)
 	userStore.dictItems.title?.forEach(element => {
 		if (element.value === "bigscreentitle") {
@@ -343,18 +351,34 @@
 
 	function updateRealTime() {
 		//console.log(`output->瀹氭椂鍒锋柊鏁版嵁`)
-		eqps.value.forEach((item) => {
-			queryRealTime(item)
+		zhengqi.value = 0;
+		dianneng.value = 0
+
+	 new Promise(async function(resolve){
+
+		await	eqps.value.forEach(async (item) => {
+			 await queryRealTime(item)
+			})
+			resolve()
+
+			console.log("鎵ц瀹屾垚");
+		}).then(()=>{
+			console.log("then:::::" + dianneng.value,zhengqi.value );
+			
+			steam.value = zhengqi.value
+			watt.value = dianneng.value
 		})
+
+		
 	}
 
-	function queryRealTime(eqp: dryEquipment) {
-		
+	async function queryRealTime(eqp: dryEquipment) {
+		console.log("sdkfjlasjdflkajsldfjlsd")
 		let tenantId = userStore.getTenant
 		let eqpCode = eqp.code
 		let queryRealTimeUrl = '/dry/real/getRealTimeData'
-		defHttp.get({ url: queryRealTimeUrl, params: { tenantid: tenantId, machineid: eqpCode } }).then((res) => {
-			//console.log(`output->res`, res)
+	 await	defHttp.get({ url: queryRealTimeUrl, params: { tenantid: tenantId, machineid: eqpCode } }).then( async (res) => {
+			console.log(`output->res`, res)
 			if (res && res.trendVo) {
 				res.tempValue = [res.windTemp, 100]
 				res.totalRemain = res.remain
@@ -367,6 +391,11 @@
 				}
 				
 				res.percent = ((res.dryTime / (res.dryTime + res.totalRemain)) * 100).toFixed(2)
+				envHum.value = res.envHum
+				envTemp.value = res.envTemp
+				zhengqi.value += res.steam
+				dianneng.value += res.watt
+				console.log("zhengqi:::" , res.steam);
 			} else {
 				res = {
 					tempValue: [0, 100],
@@ -627,7 +656,7 @@
 	}
  
 	.stat_value {
-		font-size: 32px
+		font-size: 28px
 	}
 
 	.herb_weight {
diff --git a/src/views/dry/components/DryOpcDeviceForm.vue b/src/views/dry/components/DryOpcDeviceForm.vue
new file mode 100644
index 0000000..fbd7533
--- /dev/null
+++ b/src/views/dry/components/DryOpcDeviceForm.vue
@@ -0,0 +1,70 @@
+<template>
+    <div style="min-height: 400px">
+        <BasicForm @register="registerForm"></BasicForm>
+        <div style="width: 100%;text-align: center" v-if="!formDisabled">
+            <a-button @click="submitForm" pre-icon="ant-design:check" type="primary">鎻� 浜�</a-button>
+        </div>
+    </div>
+</template>
+
+<script lang="ts">
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {computed, defineComponent} from 'vue';
+    import {defHttp} from '/@/utils/http/axios';
+    import { propTypes } from '/@/utils/propTypes';
+    import {getBpmFormSchema} from '../dataDefine/DryOpcDevice.data';
+    import {saveOrUpdate} from '../api/DryOpcDevice.api';
+    
+    export default defineComponent({
+        name: "DryOpcDeviceForm",
+        components:{
+            BasicForm
+        },
+        props:{
+            formData: propTypes.object.def({}),
+            formBpm: propTypes.bool.def(true),
+        },
+        setup(props){
+            const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
+                labelWidth: 150,
+                schemas: getBpmFormSchema(props.formData),
+                showActionButtonGroup: false,
+                baseColProps: {span: 24}
+            });
+
+            const formDisabled = computed(()=>{
+                if(props.formData.disabled === false){
+                    return false;
+                }
+                return true;
+            });
+
+            let formData = {};
+            const queryByIdUrl = '/dry/dryOpcDevice/queryById';
+            async function initFormData(){
+                let params = {id: props.formData.dataId};
+                const data = await defHttp.get({url: queryByIdUrl, params});
+                formData = {...data}
+                //璁剧疆琛ㄥ崟鐨勫��
+                await setFieldsValue(formData);
+                //榛樿鏄鐢�
+                await setProps({disabled: formDisabled.value})
+            }
+
+            async function submitForm() {
+                let data = getFieldsValue();
+                let params = Object.assign({}, formData, data);
+                console.log('琛ㄥ崟鏁版嵁', params)
+                await saveOrUpdate(params, true)
+            }
+
+            initFormData();
+            
+            return {
+                registerForm,
+                formDisabled,
+                submitForm,
+            }
+        }
+    });
+</script>
\ No newline at end of file
diff --git a/src/views/dry/components/DryOpcDeviceModal.vue b/src/views/dry/components/DryOpcDeviceModal.vue
new file mode 100644
index 0000000..96d8c7c
--- /dev/null
+++ b/src/views/dry/components/DryOpcDeviceModal.vue
@@ -0,0 +1,66 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
+      <BasicForm @register="registerForm"/>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {formSchema} from '../dataDefine/DryOpcDevice.data';
+    import {saveOrUpdate} from '../api/DryOpcDevice.api';
+    // Emits澹版槑
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    //琛ㄥ崟閰嶇疆
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        //labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+        baseColProps: {span: 24}
+    });
+    //琛ㄥ崟璧嬪��
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //閲嶇疆琛ㄥ崟
+        await resetFields();
+        setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //琛ㄥ崟璧嬪��
+            await setFieldsValue({
+                ...data.record,
+            });
+        }
+        // 闅愯棌搴曢儴鏃剁鐢ㄦ暣涓〃鍗�
+       setProps({ disabled: !data?.showFooter })
+    });
+    //璁剧疆鏍囬
+    const title = computed(() => (!unref(isUpdate) ? '鏂板' : '缂栬緫'));
+    //琛ㄥ崟鎻愪氦浜嬩欢
+    async function handleSubmit(v) {
+        try {
+            let values = await validate();
+            setModalProps({confirmLoading: true});
+            //鎻愪氦琛ㄥ崟
+            await saveOrUpdate(values, isUpdate.value);
+            //鍏抽棴寮圭獥
+            closeModal();
+            //鍒锋柊鍒楄〃
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+	/** 鏃堕棿鍜屾暟瀛楄緭鍏ユ鏍峰紡 */
+  :deep(.ant-input-number){
+		width: 100%
+	}
+
+	:deep(.ant-calendar-picker){
+		width: 100%
+	}
+</style>
\ No newline at end of file
diff --git a/src/views/dry/dataDefine/DryOpcDevice.data.ts b/src/views/dry/dataDefine/DryOpcDevice.data.ts
new file mode 100644
index 0000000..ccb1c0d
--- /dev/null
+++ b/src/views/dry/dataDefine/DryOpcDevice.data.ts
@@ -0,0 +1,109 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+//鍒楄〃鏁版嵁
+export const columns: BasicColumn[] = [
+   {
+    title: '鍚嶇О',
+    align:"center",
+    dataIndex: 'name'
+   },
+   {
+    title: '鐐逛綅鏍囪瘑',
+    align:"center",
+    dataIndex: 'identifier'
+   },
+   {
+    title: '鎺掑簭',
+    align:"center",
+    dataIndex: 'sortOrder'
+   },
+   {
+    title: '绫诲瀷',
+    align:"center",
+    dataIndex: 'type_dictText'
+   },
+];
+//鏌ヨ鏁版嵁
+export const searchFormSchema: FormSchema[] = [
+	{
+      label: "鍚嶇О",
+      field: 'name',
+      component: 'Input',
+      colProps: {span: 6},
+ 	},
+	{
+      label: "绫诲瀷",
+      field: 'type',
+      component: 'JDictSelectTag',
+      componentProps:{
+          dictCode:"device_type"
+      },
+      colProps: {span: 6},
+ 	},
+];
+//琛ㄥ崟鏁版嵁
+export const formSchema: FormSchema[] = [
+  {
+    label: '鍚嶇О',
+    field: 'name',
+    component: 'Input',
+    dynamicRules: ({model,schema}) => {
+          return [
+                 { required: true, message: '璇疯緭鍏ュ悕绉�!'},
+          ];
+     },
+  },
+  {
+    label: '鐐逛綅鏍囪瘑',
+    field: 'identifier',
+    component: 'Input',
+    dynamicRules: ({model,schema}) => {
+          return [
+                 { required: true, message: '璇疯緭鍏ョ偣浣嶆爣璇�!'},
+          ];
+     },
+  },
+  {
+    label: '鎺掑簭',
+    field: 'sortOrder',
+    component: 'InputNumber',
+    dynamicRules: ({model,schema}) => {
+          return [
+                 { required: true, message: '璇疯緭鍏ユ帓搴�!'},
+          ];
+     },
+  },
+  {
+    label: '绫诲瀷',
+    field: 'type',
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"device_type"
+     },
+    dynamicRules: ({model,schema}) => {
+          return [
+                 { required: true, message: '璇疯緭鍏ョ被鍨�!'},
+          ];
+     },
+  },
+	// TODO 涓婚敭闅愯棌瀛楁锛岀洰鍓嶅啓姝讳负ID
+	{
+	  label: '',
+	  field: 'id',
+	  component: 'Input',
+	  show: false
+	},
+];
+
+
+
+/**
+* 娴佺▼琛ㄥ崟璋冪敤杩欎釜鏂规硶鑾峰彇formSchema
+* @param param
+*/
+export function getBpmFormSchema(_formData): FormSchema[]{
+  // 榛樿鍜屽師濮嬭〃鍗曚繚鎸佷竴鑷� 濡傛灉娴佺▼涓厤缃簡鏉冮檺鏁版嵁锛岃繖閲岄渶瑕佸崟鐙鐞唂ormSchema
+  return formSchema;
+}
\ No newline at end of file
diff --git a/src/views/dry/sql/DryOpcDevice_menu_insert.sql b/src/views/dry/sql/DryOpcDevice_menu_insert.sql
new file mode 100644
index 0000000..c30a1b8
--- /dev/null
+++ b/src/views/dry/sql/DryOpcDevice_menu_insert.sql
@@ -0,0 +1,26 @@
+-- 娉ㄦ剰锛氳椤甸潰瀵瑰簲鐨勫墠鍙扮洰褰曚负views/dry鏂囦欢澶逛笅
+-- 濡傛灉浣犳兂鏇存敼鍒板叾浠栫洰褰曪紝璇蜂慨鏀箂ql涓璫omponent瀛楁瀵瑰簲鐨勫��
+
+
+INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external) 
+VALUES ('2023112802425240080', NULL, 'dry_opc_device', '/dry/dryOpcDeviceList', 'dry/DryOpcDeviceList', NULL, NULL, 0, NULL, '1', 0.00, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0, 'admin', '2023-11-28 14:42:08', NULL, NULL, 0);
+
+-- 鏉冮檺鎺у埗sql
+-- 鏂板
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2023112802425240081', '2023112802425240080', '娣诲姞dry_opc_device', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_opc_device:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-11-28 14:42:08', NULL, NULL, 0, 0, '1', 0);
+-- 缂栬緫
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2023112802425240082', '2023112802425240080', '缂栬緫dry_opc_device', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_opc_device:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-11-28 14:42:08', NULL, NULL, 0, 0, '1', 0);
+-- 鍒犻櫎
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2023112802425240083', '2023112802425240080', '鍒犻櫎dry_opc_device', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_opc_device:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-11-28 14:42:08', NULL, NULL, 0, 0, '1', 0);
+-- 鎵归噺鍒犻櫎
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2023112802425240084', '2023112802425240080', '鎵归噺鍒犻櫎dry_opc_device', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_opc_device:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-11-28 14:42:08', NULL, NULL, 0, 0, '1', 0);
+-- 瀵煎嚭excel
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2023112802425240085', '2023112802425240080', '瀵煎嚭excel_dry_opc_device', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_opc_device:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-11-28 14:42:08', NULL, NULL, 0, 0, '1', 0);
+-- 瀵煎叆excel
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2023112802425240086', '2023112802425240080', '瀵煎叆excel_dry_opc_device', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_opc_device:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-11-28 14:42:08', NULL, NULL, 0, 0, '1', 0);
\ No newline at end of file

--
Gitblit v1.9.3