瀏覽代碼

优化自检详情页代码结构

xujunjie 1 年之前
父節點
當前提交
22ef392469
共有 26 個文件被更改,包括 1909 次插入1696 次删除
  1. 5 0
      .umirc.ts
  2. 二進制
      src/assets/eqSelfInspention/tooltip.png
  3. 二進制
      src/assets/home/i.png
  4. 二進制
      src/assets/keyRemove.png
  5. 5 0
      src/components/PageContent/index.js
  6. 10 1658
      src/pages/EqSelfInspection/components/Detail.js
  7. 18 0
      src/pages/EqSelfInspection/components/PatrolReportDetail.less
  8. 176 0
      src/pages/EqSelfInspection/components/Table/DeviceTable.js
  9. 211 0
      src/pages/EqSelfInspection/components/Table/DosingFlowCom.js
  10. 11 0
      src/pages/EqSelfInspection/components/Table/Empty.js
  11. 92 0
      src/pages/EqSelfInspection/components/Table/ErrorHandleModal.js
  12. 210 0
      src/pages/EqSelfInspection/components/Table/LiquidLevelCom.js
  13. 207 0
      src/pages/EqSelfInspection/components/Table/PressureGaugeCom.js
  14. 123 0
      src/pages/EqSelfInspection/components/Table/ReportCom.js
  15. 95 0
      src/pages/EqSelfInspection/components/Table/ReportDumCom.js
  16. 116 0
      src/pages/EqSelfInspection/components/Table/WarningTable.js
  17. 208 0
      src/pages/EqSelfInspection/components/Table/WaterInCom.js
  18. 209 0
      src/pages/EqSelfInspection/components/Table/WaterQualityCom.js
  19. 2 2
      src/pages/Home/ChemCostComparison.js
  20. 3 3
      src/pages/Home/EnergyCostComparison.js
  21. 49 32
      src/pages/Home/index.js
  22. 23 0
      src/pages/Home/index.less
  23. 5 1
      src/pages/Menu/index.js
  24. 81 0
      src/pages/SafetyManagement/Command/index.js
  25. 44 0
      src/pages/SafetyManagement/Command/index.less
  26. 6 0
      src/services/safety.js

+ 5 - 0
.umirc.ts

@@ -204,6 +204,11 @@ export default defineConfig({
       path: '/safety/:projectId', ///safety management
       component: './SafetyManagement',
     },
+    {
+      name: '安全管理-口令',
+      path: '/safety/command/:projectId', ///safety management
+      component: './SafetyManagement/Command',
+    },
     // 视频图片预览
     {
       path: '/alarm/preview',

二進制
src/assets/eqSelfInspention/tooltip.png


二進制
src/assets/home/i.png


二進制
src/assets/keyRemove.png


+ 5 - 0
src/components/PageContent/index.js

@@ -3,6 +3,7 @@ import { CloseCircleFilled, LeftOutlined } from '@ant-design/icons';
 import { history } from '@umijs/max';
 import { ConfigProvider } from 'antd';
 import locale from 'antd/es/locale/zh_CN';
+import { useEffect } from 'react';
 import styles from './index.less';
 
 export default (props) => {
@@ -21,6 +22,10 @@ export default (props) => {
     history.back();
   };
 
+  useEffect(() => {
+    document.body.style.backgroundColor = 'transparent';
+  }, []);
+
   return (
     <ConfigProvider locale={locale}>
       <div className={styles.page} style={style}>

File diff suppressed because it is too large
+ 10 - 1658
src/pages/EqSelfInspection/components/Detail.js


+ 18 - 0
src/pages/EqSelfInspection/components/PatrolReportDetail.less

@@ -22,6 +22,24 @@
   border-radius: 50%;
   display: inline-block;
 }
+.tipTitle {
+  display: flex;
+  i {
+    width: 0.28rem;
+    height: 0.28rem;
+    margin-left: 0.1rem;
+    display: block;
+    background: url('@/assets/eqSelfInspention/tooltip.png') no-repeat center;
+    background-size: 100% 100%;
+  }
+}
+.popoverContent {
+  font-size: 20px;
+  p {
+    margin-bottom: 0;
+    line-height: 36px;
+  }
+}
 .detailCard {
   // margin: 0.2rem 0;
   margin-bottom: 0.3rem;

+ 176 - 0
src/pages/EqSelfInspection/components/Table/DeviceTable.js

@@ -0,0 +1,176 @@
+import ThresholdDetail from '@/components/ThresholdDetail';
+import ThresholdModal from '@/components/ThresholdDetail/ThresholdModal';
+import { changeRecordStatus } from '@/services/eqSelfInspection';
+import { UnityAction } from '@/utils/utils';
+import { Table, message } from 'antd';
+import { useState } from 'react';
+import styles from '../PatrolReportDetail.less';
+import ErrorHandleModal from './ErrorHandleModal';
+import Empty from './Empty';
+
+export default function DeviceTable(props) {
+  const {
+    onClickItem,
+    data = {},
+    items,
+    userList,
+    type,
+  } = props;
+  console.log(items);
+  const [loading, setLoading] = useState(false);
+  const [visible, setVisible] = useState(false);
+  const [errVisible, setErrVisible] = useState(false);
+  const [currentItem, setCurrentItem] = useState({});
+  const isSensor = type == 'sensor';
+
+  const onClickThreshold = (record) => {
+    setCurrentItem(record);
+    setVisible(true);
+  };
+  const onClickError = (record) => {
+    setCurrentItem(record);
+    setErrVisible(true);
+  };
+  const handleError = async (values) => {
+    setLoading(true);
+    let res = await changeRecordStatus({
+      ...values,
+      Id: currentItem.Id,
+      DeviceCode: currentItem.DeviceCode,
+      DeviceName: currentItem.DeviceName,
+      RecordId: data.Id,
+      RepairMan: values.RepairMan * 1,
+    });
+    setLoading(false);
+    if (res) {
+      message.success('操作成功');
+      setErrVisible(false);
+    }
+  };
+  const columns = [
+    {
+      title: '设备名称',
+      width: '20%',
+      dataIndex: 'DeviceName',
+    },
+    {
+      title: '巡检项',
+      key: 'TemplateItem.Name',
+      dataIndex: ['TemplateItem', 'Name'],
+    },
+    // {
+    //   title: '设备位号',
+    //   width: '16%',
+    //   dataIndex: 'DeviceCode',
+    // },
+    {
+      title: '设定值范围',
+      render: (record) => (
+        <ThresholdDetail
+          current={record.Value || 0}
+          data={record || {}}
+          // onClick={() => onClickThreshold(record)}
+        />
+      ),
+    },
+    {
+      title: '状态',
+      dataIndex: 'Status',
+      width: '1.25rem',
+      render: (Status) => {
+        switch (Status) {
+          case -1:
+          case 0:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#12CEB3' }}
+                ></i>
+                正常
+              </div>
+            );
+          case 1:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FE5850' }}
+                ></i>
+                异常
+              </div>
+            );
+          case 2:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FFE26D' }}
+                ></i>
+                警告
+              </div>
+            );
+        }
+      },
+    },
+  ];
+  const handleClickItem = (data) => {
+    if (!isSensor) {
+      onClickItem(`DeviceTable-${data.Id}`, {
+        type: data.Status,
+        deviceCode: data.DeviceCode,
+      });
+    } else {
+      onClickItem(`DeviceTable-${data.Id}`, {
+        // type: data.Status,
+        deviceCode: data.DeviceCode,
+        value: Number(data.Value || 0),
+        threshold: data.JsonNumThreshold,
+      });
+      UnityAction.sendMsg('SinglePowerEnvironFromWeb', JSON.stringify(data));
+    }
+  };
+
+  // useEffect(() => {
+  //   console.log('温控', items);
+  //   if (isSensor)
+  //     UnityAction.sendMsg('PowerEnvironsFromWeb', JSON.stringify(items));
+  // }, [items]);
+
+  // if (!isSensor) {
+  //   columns.push({
+  //     title: '操作',
+  //     render: (record) =>
+  //       record.Status == 1 && (
+  //         <a style={{ color: '#FE5850' }} onClick={() => onClickError(record)}>
+  //           异常处理
+  //         </a>
+  //       ),
+  //   });
+  // }
+
+  return (
+    <div>
+      <Table
+        columns={columns}
+        dataSource={items}
+        rowKey="Id"
+        locale={{
+          emptyText: <Empty />,
+        }}
+        pagination={false}
+      />
+      <ThresholdModal
+        open={visible}
+        data={currentItem.JsonNumThreshold}
+        onClose={() => setVisible(false)}
+      />
+      <ErrorHandleModal
+        open={errVisible}
+        userList={userList}
+        onCancel={() => setErrVisible(false)}
+        onOk={handleError}
+      />
+    </div>
+  );
+}

+ 211 - 0
src/pages/EqSelfInspection/components/Table/DosingFlowCom.js

@@ -0,0 +1,211 @@
+import TabsContent from '@/components/TabsContent';
+import ThresholdDetail from '@/components/ThresholdDetail';
+import { Popover, Table } from 'antd';
+import dayjs from 'dayjs';
+import { useEffect, useMemo, useState } from 'react';
+import styles from '../PatrolReportDetail.less';
+import Empty from './Empty';
+
+export default function DosingFlowCom(props) {
+  const {
+    sendMessageToUnity,
+    select,
+    allData = [],
+    title,
+    statusCheck,
+    changeStatus,
+  } = props;
+  const [activeKey, setActiveKey] = useState('1');
+
+  const handleTabsChange = (key) => {
+    setActiveKey(key);
+  };
+
+  const { errorTableData, normalData } = useMemo(() => {
+    let data = { errorTableData: [], normalData: [] };
+    allData?.forEach((item) => {
+      if (item.status == 1 && statusCheck.includes(1)) {
+        data.errorTableData.push(item);
+      } else if (item.status == 0 && statusCheck.includes(0)) {
+        data.normalData.push(item);
+      }
+    });
+    return data;
+  }, [statusCheck, allData]);
+
+  const items = useMemo(() => {
+    let items = [];
+    let showAllTabs = statusCheck.length == 3;
+    if (showAllTabs || errorTableData.length > 0) {
+      items.push({
+        key: '1',
+        label: `异常(${errorTableData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    if (showAllTabs || normalData.length > 0) {
+      items.push({
+        key: '0',
+        label: `历史记录(${normalData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    return items;
+  }, [statusCheck, allData]);
+
+  useEffect(() => {
+    if (items.length == 0) {
+      changeStatus(0);
+    } else {
+      setActiveKey(items[0].key);
+      changeStatus(1);
+    }
+  }, [items]);
+
+  const content = (
+    <div className={styles.popoverContent}>
+      <p>差值:液位计流量与流量计流量的差值</p>
+      <p>比值:液位计流量与流量计流量的比值</p>
+    </div>
+  );
+  if (items.length == 0) return null;
+
+  return (
+    <div className={styles.detailCard}>
+      <div className={styles.tableTop}>
+        <div className={styles.tipTitle}>
+          加药流量校验
+          <Popover content={content}>
+            <i></i>
+          </Popover>
+        </div>
+        <TabsContent
+          active={activeKey}
+          onChange={handleTabsChange}
+          small
+          items={items}
+        ></TabsContent>
+      </div>
+
+      {activeKey === '1' && (
+        <DosingFlowTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={errorTableData}
+        />
+      )}
+      {activeKey === '0' && (
+        <DosingFlowTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={normalData}
+        />
+      )}
+    </div>
+  );
+}
+function DosingFlowTable(props) {
+  const { items } = props;
+  const columns = [
+    {
+      title: '设备名称',
+      width: '12%',
+      dataIndex: 'device_name',
+    },
+    {
+      title: '时间',
+      dataIndex: 'record_time',
+      render: (text) => {
+        if (text) {
+          return dayjs(text).format('YYYY.MM.DD HH:mm');
+        }
+        return '-';
+      },
+    },
+    {
+      title: '类型',
+      width: '15%',
+      key: 'template_item_name',
+      dataIndex: 'template_item_name',
+    },
+    {
+      title: '实际流量',
+      dataIndex: 'origin_value',
+    },
+    {
+      title: '计量流量',
+      dataIndex: 'value',
+    },
+    {
+      title: '差值/比值',
+      dataIndex: 'value',
+    },
+    {
+      title: '设定值范围',
+      width: '18%',
+      render: (record) => (
+        <ThresholdDetail
+          current={record.value || 0}
+          data={{
+            JsonNumThreshold: record?.json_num_threshold,
+            Type: record.type || 2,
+          }}
+        />
+      ),
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: '20%',
+      render: (status) => {
+        switch (status) {
+          case -1:
+          case 0:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#12CEB3' }}
+                />
+                正常
+              </div>
+            );
+          case 1:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FF8600' }}
+                />
+                异常
+              </div>
+            );
+          case 2:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FFE26D' }}
+                />
+                警告
+              </div>
+            );
+          default:
+            return null;
+        }
+      },
+    },
+  ];
+
+  return (
+    <Table
+      columns={columns}
+      dataSource={items}
+      rowKey="device_code"
+      locale={{
+        emptyText: <Empty />,
+      }}
+      pagination={false}
+    />
+  );
+}

+ 11 - 0
src/pages/EqSelfInspection/components/Table/Empty.js

@@ -0,0 +1,11 @@
+export default function Empty() {
+  return (
+    <div>
+      <img
+        src={require('@/assets/self-empty.png')}
+        style={{ margin: '0.2rem 0', width: '1rem' }}
+      />
+      <p style={{ textAlign: 'center', color: '#555' }}>自检正常</p>
+    </div>
+  );
+}

+ 92 - 0
src/pages/EqSelfInspection/components/Table/ErrorHandleModal.js

@@ -0,0 +1,92 @@
+import { DatePicker, Form, Input, Modal, Select } from 'antd';
+
+export default function ErrorHandleModal(props) {
+  const { visible, onCancel, onOk, userList } = props;
+  const [form] = Form.useForm();
+  const status = form.getFieldValue('Status');
+  const handleOk = () => {
+    form.validateFields((error, values) => {
+      if (error) return;
+      onOk({
+        ...values,
+        PlanTime: values?.PlanTime?.format('YYYY-MM-DD HH:mm:ss'),
+      });
+    });
+  };
+
+  return (
+    <Modal
+      title="异常处理"
+      open={visible}
+      onCancel={onCancel}
+      onOk={handleOk}
+      destroyOnClose
+    >
+      <Form labelCol={{ span: 7 }} wrapperCol={{ span: 16 }}>
+        <Form.Item label="异常处理备注" name="ExceptionHandling">
+          <Input.TextArea />
+        </Form.Item>
+        <Form.Item
+          label="审核状态"
+          name="Status"
+          rules={[{ required: true, message: '请选择验收状态' }]}
+        >
+          <Select style={{ width: '100%' }} placeholder="请选择验收状态">
+            <Select.Option value={1}>已派遣</Select.Option>
+            <Select.Option value={2}>已通过</Select.Option>
+          </Select>
+        </Form.Item>
+        <Form.Item
+          label="维修人"
+          name="RepairMan"
+          rules={[{ required: true, message: '请选择维修人' }]}
+        >
+          <Select
+            showSearch
+            placeholder="请选择维修人"
+            filterOption={(input, option) =>
+              option.props.children.indexOf(input) >= 0
+            }
+            style={{ width: '100%' }}
+          >
+            {userList?.map((item) => (
+              <Select.Option key={item.ID}>{item.CName}</Select.Option>
+            ))}
+          </Select>
+        </Form.Item>
+        {status == 1 && (
+          <>
+            <Form.Item
+              label="难度级别"
+              name="DifficultyLevel"
+              rules={[{ required: true, message: '请选择难度级别' }]}
+            >
+              <Select placeholder="请选择难度级别" style={{ width: '100%' }}>
+                <Select.Option value={0}>大修</Select.Option>
+                <Select.Option value={1}>项目维修</Select.Option>
+                <Select.Option value={2}>小修</Select.Option>
+              </Select>
+            </Form.Item>
+            <Form.Item
+              label="维修方式"
+              name="RepairType"
+              rules={[{ required: true, message: '请选择维修方式' }]}
+            >
+              <Select placeholder="请选择维修方式" style={{ width: '100%' }}>
+                <Select.Option value={0}>自维</Select.Option>
+                <Select.Option value={1}>外委</Select.Option>
+              </Select>
+            </Form.Item>
+            <Form.Item
+              label="计划完成日期"
+              name="PlanTime"
+              rules={[{ required: true, message: '请选择计划完成日期' }]}
+            >
+              <DatePicker inputReadOnly />
+            </Form.Item>
+          </>
+        )}
+      </Form>
+    </Modal>
+  );
+}

+ 210 - 0
src/pages/EqSelfInspection/components/Table/LiquidLevelCom.js

@@ -0,0 +1,210 @@
+import TabsContent from '@/components/TabsContent';
+import ThresholdDetail from '@/components/ThresholdDetail';
+import { Popover, Table } from 'antd';
+import dayjs from 'dayjs';
+import { useEffect, useMemo, useState } from 'react';
+import styles from '../PatrolReportDetail.less';
+import Empty from './Empty';
+
+export default function LiquidLevelCom(props) {
+  const {
+    sendMessageToUnity,
+    select,
+    allData,
+    type,
+    statusCheck,
+    changeStatus,
+  } = props;
+  const [activeKey, setActiveKey] = useState('1');
+
+  const handleTabsChange = (activeKey) => {
+    setActiveKey(activeKey);
+  };
+
+  const { errorTableData, normalData } = useMemo(() => {
+    let data = { errorTableData: [], normalData: [] };
+    allData?.forEach((item) => {
+      if (item.status == 1 && statusCheck.includes(1)) {
+        data.errorTableData.push(item);
+      } else if (item.status == 0 && statusCheck.includes(0)) {
+        data.normalData.push(item);
+      }
+    });
+    return data;
+  }, [statusCheck, allData]);
+
+  const items = useMemo(() => {
+    let items = [];
+    let showAllTabs = statusCheck.length == 3;
+    if (showAllTabs || errorTableData.length > 0) {
+      items.push({
+        key: '1',
+        label: `异常(${errorTableData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    if (showAllTabs || normalData.length > 0) {
+      items.push({
+        key: '0',
+        label: `历史记录(${normalData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    return items;
+  }, [statusCheck, allData]);
+
+  useEffect(() => {
+    if (items.length == 0) {
+      changeStatus(0);
+    } else {
+      setActiveKey(items[0].key);
+      changeStatus(1);
+    }
+  }, [items]);
+  const content = (
+    <div className={styles.popoverContent}>
+      <p>固定液位1为H1,固定液位2为H2,实际液位为H实</p>
+      <p>液位差值:液位标准值(H1)与液位实际值(H2)的差值</p>
+      <p>液位差比值:H1标准值与实际值的差值与H2的标准值与实际值的差值的比值</p>
+    </div>
+  );
+  if (items.length == 0) return null;
+
+  return (
+    <div className={styles.detailCard}>
+      <div className={styles.tableTop}>
+        <div className={styles.tipTitle}>
+          液位校验
+          <Popover content={content}>
+            <i></i>
+          </Popover>
+        </div>
+        <TabsContent
+          active={activeKey}
+          onChange={handleTabsChange}
+          small
+          items={items}
+        ></TabsContent>
+      </div>
+
+      {activeKey === '1' && (
+        <LiquidTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={errorTableData}
+          key={type}
+          type={type}
+        />
+      )}
+      {activeKey === '0' && (
+        <LiquidTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={normalData}
+          key={type}
+          type={type}
+        />
+      )}
+    </div>
+  );
+}
+
+function LiquidTable(props) {
+  const { items } = props;
+
+  const columns = [
+    {
+      title: '设备名称',
+      width: '12%',
+      dataIndex: 'device_name',
+    },
+    {
+      title: '时间',
+      dataIndex: 'record_time',
+      render: (text) => {
+        if (text) {
+          return dayjs(text).format('YYYY.MM.DD HH:mm');
+        }
+        return '-';
+      },
+    },
+    {
+      title: '类型',
+      key: 'template_item_name',
+      dataIndex: 'template_item_name',
+    },
+    {
+      title: '液位数',
+      dataIndex: 'origin_value',
+    },
+    {
+      title: '差值/比值',
+      dataIndex: 'value',
+    },
+    {
+      title: '设定值范围',
+      width: '18%',
+      render: (record) => (
+        <ThresholdDetail
+          current={record.value || 0}
+          data={{
+            JsonNumThreshold: record?.json_num_threshold,
+            Type: record.type || 2,
+          }}
+        />
+      ),
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: '1.25rem',
+      render: (status) => {
+        switch (status) {
+          case -1:
+          case 0:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#12CEB3' }}
+                ></i>
+                正常
+              </div>
+            );
+          case 1:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FFE26D' }}
+                ></i>
+                异常
+              </div>
+            );
+          case 2:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FFE26D' }}
+                ></i>
+                警告
+              </div>
+            );
+        }
+      },
+    },
+  ];
+
+  return (
+    <Table
+      columns={columns}
+      dataSource={items}
+      rowKey="device_code"
+      locale={{
+        emptyText: <Empty />,
+      }}
+      pagination={false}
+    />
+  );
+}

+ 207 - 0
src/pages/EqSelfInspection/components/Table/PressureGaugeCom.js

@@ -0,0 +1,207 @@
+import TabsContent from '@/components/TabsContent';
+import { Table } from 'antd';
+import dayjs from 'dayjs';
+import { useEffect, useMemo, useState } from 'react';
+import styles from '../PatrolReportDetail.less';
+import Empty from './Empty';
+
+function PressureGaugeTable(props) {
+  const { items } = props;
+  const columns = [
+    {
+      title: '设备名称',
+      width: '20%',
+      dataIndex: 'item_alias',
+    },
+    {
+      title: '时间范围',
+      key: 'dataRange',
+      width: '1.5rem',
+      render: (record) => {
+        if (record.query_start && record.query_end) {
+          return (
+            <>
+              {dayjs(record.query_start).format('HH:mm:ss')}
+              <br />
+              {dayjs(record.query_end).format('HH:mm:ss')}
+            </>
+          );
+        }
+        return '-';
+      },
+    },
+    {
+      title: (
+        <>
+          仪表
+          <br />
+          最小数
+        </>
+      ),
+      width: '1.25rem',
+      dataIndex: 'data_min',
+    },
+    {
+      title: (
+        <>
+          仪表
+          <br />
+          最大数
+        </>
+      ),
+      width: '1.25rem',
+      dataIndex: 'data_max',
+    },
+    {
+      title: '可能原因',
+      dataIndex: 'content',
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: '1.25rem',
+      render: (status) => {
+        switch (status) {
+          case -1:
+          case 0:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#12CEB3' }}
+                />
+                正常
+              </div>
+            );
+          case 1:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FF8600' }}
+                />
+                异常
+              </div>
+            );
+          case 2:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FFE26D' }}
+                />
+                警告
+              </div>
+            );
+          default:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FF8600' }}
+                />
+                异常
+              </div>
+            );
+        }
+      },
+    },
+  ];
+  return (
+    <Table
+      columns={columns}
+      dataSource={items}
+      rowKey="device_code"
+      locale={{
+        emptyText: <Empty />,
+      }}
+      pagination={false}
+    />
+  );
+}
+
+export default function PressureGaugeCom(props) {
+  const {
+    sendMessageToUnity,
+    select,
+    allData = [],
+    title,
+    statusCheck,
+    changeStatus,
+  } = props;
+  const [activeKey, setActiveKey] = useState('1');
+
+  const handleTabsChange = (key) => {
+    setActiveKey(key);
+  };
+
+  const { errorTableData, normalData } = useMemo(() => {
+    let data = { errorTableData: [], normalData: [] };
+    allData?.forEach((item) => {
+      if (item.status == 1 && statusCheck.includes(1)) {
+        data.errorTableData.push(item);
+      } else if (item.status == 0 && statusCheck.includes(0)) {
+        data.normalData.push(item);
+      }
+    });
+    return data;
+  }, [statusCheck, allData]);
+
+  const items = useMemo(() => {
+    let items = [];
+    let showAllTabs = statusCheck.length == 3;
+    if (showAllTabs || errorTableData.length > 0) {
+      items.push({
+        key: '1',
+        label: `异常(${errorTableData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    if (showAllTabs || normalData.length > 0) {
+      items.push({
+        key: '0',
+        label: `正常(${normalData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    return items;
+  }, [statusCheck, allData]);
+
+  useEffect(() => {
+    if (items.length == 0) {
+      changeStatus(0);
+    } else {
+      setActiveKey(items[0].key);
+      changeStatus(1);
+    }
+  }, [items]);
+
+  if (items.length == 0) return null;
+  return (
+    <div className={styles.detailCard}>
+      <div className={styles.tableTop}>
+        {title}
+        <TabsContent
+          active={activeKey}
+          onChange={handleTabsChange}
+          small
+          items={items}
+        ></TabsContent>
+      </div>
+      {activeKey === '1' && (
+        <PressureGaugeTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={errorTableData}
+        />
+      )}
+      {activeKey === '0' && (
+        <PressureGaugeTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={normalData}
+        />
+      )}
+    </div>
+  );
+}

+ 123 - 0
src/pages/EqSelfInspection/components/Table/ReportCom.js

@@ -0,0 +1,123 @@
+import TabsContent from '@/components/TabsContent';
+import { useEffect, useMemo, useState } from 'react';
+import styles from '../PatrolReportDetail.less';
+import DeviceTable from './DeviceTable';
+import WarningTable from './WarningTable';
+
+export default function ReportCom(props) {
+  const {
+    sendMessageToUnity,
+    select,
+    allData,
+    userList,
+    type,
+    title,
+    data,
+    statusCheck,
+    changeStatus,
+  } = props;
+  const [activeKey, setActiveKey] = useState('1');
+  const handleTabsChange = (activeKey) => {
+    setActiveKey(activeKey);
+  };
+
+  const { warningTableData, errorTableData, normalData } = useMemo(() => {
+    let data = { warningTableData: [], errorTableData: [], normalData: [] };
+    allData?.forEach((item) => {
+      if (item.Status == 1 && statusCheck.includes(1)) {
+        data.errorTableData.push(item);
+      } else if (item.Status == 2 && statusCheck.includes(2)) {
+        data.warningTableData.push(item);
+      } else if (statusCheck.includes(0)) {
+        data.normalData.push(item);
+      }
+    });
+    return data;
+  }, [statusCheck, allData]);
+
+  const items = useMemo(() => {
+    let items = [];
+    let showAllTabs = statusCheck.length == 3;
+    if (showAllTabs || errorTableData.length > 0) {
+      items.push({
+        key: '1',
+        label: `异常(${errorTableData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    if (showAllTabs || warningTableData.length > 0) {
+      items.push({
+        key: '2',
+        label: `警告(${warningTableData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    if (showAllTabs || normalData.length > 0) {
+      items.push({
+        key: '0',
+        label: `正常(${normalData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    return items;
+  }, [statusCheck, allData]);
+
+  useEffect(() => {
+    if (items.length == 0) {
+      changeStatus(0);
+    } else {
+      setActiveKey(items[0].key);
+      changeStatus(1);
+    }
+  }, [items]);
+
+  if (items.length == 0) return null;
+
+  return (
+    <div className={styles.detailCard}>
+      <div className={styles.tableTop}>
+        {title}
+        <TabsContent
+          active={activeKey}
+          onChange={handleTabsChange}
+          small={true}
+          items={items}
+        ></TabsContent>
+      </div>
+
+      {activeKey == '1' && (
+        <WarningTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={errorTableData}
+          key={type}
+          data={data}
+          type={type}
+          userList={userList}
+        />
+      )}
+      {activeKey == '2' && (
+        <WarningTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={warningTableData}
+          key={type}
+          data={data}
+          type={type}
+          userList={userList}
+        />
+      )}
+      {activeKey == '0' && (
+        <DeviceTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={allData}
+          data={data}
+          key={type}
+          type={type}
+          userList={userList}
+        />
+      )}
+    </div>
+  );
+}

+ 95 - 0
src/pages/EqSelfInspection/components/Table/ReportDumCom.js

@@ -0,0 +1,95 @@
+import { Table } from 'antd';
+import dayjs from 'dayjs';
+import { useEffect, useMemo } from 'react';
+import ReactZmage from 'react-zmage';
+import styles from '../PatrolReportDetail.less';
+import Empty from './Empty';
+
+export default function ReportDumCom(props) {
+  const { data = [], title, statusCheck, changeStatus } = props;
+  const errorCount = data?.length || 0;
+  const columns = [
+    {
+      title: '报警时间',
+      dataIndex: 'event_time',
+      render: (time) => dayjs(time).format('YYYY-MM-DD HH:mm:ss'),
+    },
+    {
+      title: '设备名称',
+      dataIndex: 'device_name',
+    },
+    {
+      title: '报警类型',
+      dataIndex: 'event_type',
+      // render: type => alarmType[type],
+    },
+    {
+      title: '报警图片',
+      render: (item) => (
+        <ReactZmage
+          controller={{
+            // 关闭按钮
+            close: true,
+            // 旋转按钮
+            rotate: true,
+            // 缩放按钮
+            zoom: false,
+            // 下载按钮
+            download: false,
+            // 翻页按钮
+            flip: false,
+            // 多页指示
+            pagination: false,
+          }}
+          backdrop="rgba(255,255,255,0.5)"
+          style={{ height: '0.9rem' }}
+          src={item.path}
+        />
+      ),
+    },
+  ];
+
+  const show = useMemo(() => {
+    if (statusCheck.length != 3) {
+      // 不显示异常数据时,隐藏次模块
+      if (!statusCheck.includes(1)) return null;
+      // 过滤异常并且此模块没有异常数据时,不显示此模块
+      if (statusCheck.includes(1) && errorCount == 0) return null;
+    }
+    return true;
+  }, [statusCheck, errorCount]);
+
+  useEffect(() => {
+    if (show) {
+      changeStatus(1);
+    } else {
+      changeStatus(0);
+    }
+  }, [show]);
+
+  if (!show) return null;
+  return (
+    <div style={{ marginBottom: '0.3rem' }}>
+      <div className={styles.tabBarExtraContent}>
+        <div className={styles.text} style={{ width: '60%' }}>
+          {title}
+        </div>
+        <div className={styles.abnormal}>
+          <div className={styles.text} style={{ float: 'right' }}>
+            异常({errorCount})
+          </div>
+        </div>
+      </div>
+      <Table
+        bordered
+        rowKey="event_time"
+        columns={columns}
+        dataSource={data}
+        locale={{
+          emptyText: <Empty />,
+        }}
+        pagination={false}
+      />
+    </div>
+  );
+}

+ 116 - 0
src/pages/EqSelfInspection/components/Table/WarningTable.js

@@ -0,0 +1,116 @@
+import ThresholdDetail from '@/components/ThresholdDetail';
+import ThresholdModal from '@/components/ThresholdDetail/ThresholdModal';
+import { changeRecordStatus } from '@/services/eqSelfInspection';
+import { Table, message } from 'antd';
+import { useState } from 'react';
+import ErrorHandleModal from './ErrorHandleModal';
+import styles from '../PatrolReportDetail.less';
+import Empty from './Empty';
+
+export default function WarningTable(props) {
+  const { data, userList, items } = props;
+  const [loading, setLoading] = useState(false);
+  const [visible, setVisible] = useState(false);
+  const [errVisible, setErrVisible] = useState(false);
+  const [currentItem, setCurrentItem] = useState({});
+
+  const handleError = async (values) => {
+    setLoading(true);
+    var res = await changeRecordStatus({
+      ...values,
+      Id: currentItem.Id,
+      DeviceCode: currentItem.DeviceCode,
+      DeviceName: currentItem.DeviceName,
+      RecordId: data.Id,
+      RepairMan: values.RepairMan * 1,
+    });
+    setLoading(false);
+    if (res) {
+      message.success('操作成功');
+      setErrVisible(false);
+    }
+  };
+  const columns = [
+    {
+      title: '设备名称',
+      width: '20%',
+      dataIndex: 'DeviceName',
+    },
+    {
+      title: '巡检项',
+      dataIndex: ['TemplateItem', 'Name'],
+    },
+    {
+      title: '设定值范围',
+      width: '30%',
+      render: (record) => (
+        <ThresholdDetail current={record.Value || 0} data={record || {}} />
+      ),
+    },
+    {
+      title: '状态',
+      dataIndex: 'Status',
+      width: '1.25rem',
+      render: (Status) => {
+        switch (Status) {
+          case -1:
+          case 0:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#12CEB3' }}
+                ></i>
+                正常
+              </div>
+            );
+          case 1:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FE5850' }}
+                ></i>
+                异常
+              </div>
+            );
+          case 2:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FFE26D' }}
+                ></i>
+                警告
+              </div>
+            );
+        }
+      },
+    },
+  ];
+
+  return (
+    <div>
+      <Table
+        columns={columns}
+        dataSource={items}
+        rowKey="Id"
+        locale={{
+          emptyText: <Empty />,
+        }}
+        pagination={false}
+      />
+      <ThresholdModal
+        open={visible}
+        data={currentItem.JsonNumThreshold}
+        onClose={() => setVisible(false)}
+      />
+      <ErrorHandleModal
+        open={errVisible}
+        userList={userList}
+        onCancel={() => setErrVisible(false)}
+        onOk={handleError}
+      />
+    </div>
+  );
+}

+ 208 - 0
src/pages/EqSelfInspection/components/Table/WaterInCom.js

@@ -0,0 +1,208 @@
+import TabsContent from '@/components/TabsContent';
+import ThresholdDetail from '@/components/ThresholdDetail';
+import { Popover, Table } from 'antd';
+import dayjs from 'dayjs';
+import { useEffect, useMemo, useState } from 'react';
+import styles from '../PatrolReportDetail.less';
+import Empty from './Empty';
+
+export default function WaterInCom(props) {
+  const {
+    sendMessageToUnity,
+    select,
+    allData = [],
+    title,
+    statusCheck,
+    changeStatus,
+  } = props;
+  const [activeKey, setActiveKey] = useState('1');
+
+  const handleTabsChange = (key) => {
+    setActiveKey(key);
+  };
+
+  const { errorTableData, normalData } = useMemo(() => {
+    let data = { errorTableData: [], normalData: [] };
+    allData?.forEach((item) => {
+      if (item.status == 1 && statusCheck.includes(1)) {
+        data.errorTableData.push(item);
+      } else if (item.status == 0 && statusCheck.includes(0)) {
+        data.normalData.push(item);
+      }
+    });
+    return data;
+  }, [statusCheck, allData]);
+
+  const items = useMemo(() => {
+    let items = [];
+    let showAllTabs = statusCheck.length == 3;
+    if (showAllTabs || errorTableData.length > 0) {
+      items.push({
+        key: '1',
+        label: `异常(${errorTableData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    if (showAllTabs || normalData.length > 0) {
+      items.push({
+        key: '0',
+        label: `正常(${normalData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    return items;
+  }, [statusCheck, allData]);
+
+  useEffect(() => {
+    if (items.length == 0) {
+      changeStatus(0);
+    } else {
+      setActiveKey(items[0].key);
+      changeStatus(1);
+    }
+  }, [items]);
+  const content = (
+    <div className={styles.popoverContent}>
+      <p>进出水实际流量=超滤总进水流量-反洗水池的补水流量-反渗透总进水流量</p>
+      <p>差值:进出水实际流量与流量计流量的差值</p>
+    </div>
+  );
+  if (items.length == 0) return null;
+  return (
+    <div className={styles.detailCard}>
+      <div className={styles.tableTop}>
+        <div className={styles.tipTitle}>
+          进出水流量校验
+          <Popover content={content}>
+            <i></i>
+          </Popover>
+        </div>
+        <TabsContent
+          active={activeKey}
+          onChange={handleTabsChange}
+          small
+          items={items}
+        ></TabsContent>
+      </div>
+      {activeKey === '1' && (
+        <WaterInTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={errorTableData}
+        />
+      )}
+      {activeKey === '0' && (
+        <WaterInTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={normalData}
+        />
+      )}
+    </div>
+  );
+}
+function WaterInTable(props) {
+  const { items } = props;
+  const columns = [
+    {
+      title: '设备名称',
+      width: '20%',
+      dataIndex: 'item_alias',
+    },
+    {
+      title: '差值',
+      // width: '15%',
+      dataIndex: 'current_val',
+    },
+    {
+      title: '时间',
+      // width: '15%',
+      dataIndex: 'create_time',
+      render: (text) => {
+        if (text) {
+          return dayjs(text).format('HH:mm:ss');
+        }
+        return '-';
+      },
+    },
+    {
+      title: '设定值范围',
+      width: '30%',
+      render: (record) => (
+        <ThresholdDetail
+          current={record.current_val || 0}
+          data={{
+            JsonNumThreshold: {
+              exception: [
+                { ThresholdValue: record?.thresholds, ThresholdType: 1 },
+              ],
+            },
+            Type: 2,
+          }}
+        />
+      ),
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: '1.25rem',
+      render: (status) => {
+        switch (status) {
+          case -1:
+          case 0:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#12CEB3' }}
+                />
+                正常
+              </div>
+            );
+          case 1:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FF8600' }}
+                />
+                异常
+              </div>
+            );
+          case 2:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FFE26D' }}
+                />
+                警告
+              </div>
+            );
+          default:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FF8600' }}
+                />
+                异常
+              </div>
+            );
+        }
+      },
+    },
+  ];
+
+  return (
+    <Table
+      columns={columns}
+      dataSource={items}
+      rowKey="device_code"
+      locale={{
+        emptyText: <Empty />,
+      }}
+      pagination={false}
+    />
+  );
+}

+ 209 - 0
src/pages/EqSelfInspection/components/Table/WaterQualityCom.js

@@ -0,0 +1,209 @@
+import TabsContent from '@/components/TabsContent';
+import { Table } from 'antd';
+import dayjs from 'dayjs';
+import { useEffect, useMemo, useState } from 'react';
+import Empty from './Empty';
+import styles from '../PatrolReportDetail.less';
+
+function WaterQualityTable(props) {
+  const { items } = props;
+  const columns = [
+    {
+      title: '设备名称',
+      width: '20%',
+      dataIndex: 'item_alias',
+    },
+    {
+      title: '时间范围',
+      key: 'dataRange',
+      width: '1.5rem',
+      render: (record) => {
+        if (record.query_start && record.query_end) {
+          return (
+            <>
+              {dayjs(record.query_start).format('HH:mm:ss')}
+              <br />
+              {dayjs(record.query_end).format('HH:mm:ss')}
+            </>
+          );
+        }
+        return '-';
+      },
+    },
+    {
+      title: (
+        <>
+          仪表
+          <br />
+          最小数
+        </>
+      ),
+      width: '1.25rem',
+      dataIndex: 'data_min',
+    },
+    {
+      title: (
+        <>
+          仪表
+          <br />
+          最大数
+        </>
+      ),
+      width: '1.25rem',
+      dataIndex: 'data_max',
+    },
+    {
+      title: '可能原因',
+      dataIndex: 'content',
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: '1.25rem',
+      render: (status) => {
+        switch (status) {
+          case -1:
+          case 0:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#12CEB3' }}
+                />
+                正常
+              </div>
+            );
+          case 1:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FF8600' }}
+                />
+                异常
+              </div>
+            );
+          case 2:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FFE26D' }}
+                />
+                警告
+              </div>
+            );
+          default:
+            return (
+              <div>
+                <i
+                  className={styles.iconStatus}
+                  style={{ background: '#FF8600' }}
+                />
+                异常
+              </div>
+            );
+        }
+      },
+    },
+  ];
+
+  return (
+    <Table
+      columns={columns}
+      dataSource={items}
+      rowKey="device_code"
+      locale={{
+        emptyText: <Empty />,
+      }}
+      pagination={false}
+    />
+  );
+}
+
+export default function WaterQualityCom(props) {
+  const {
+    sendMessageToUnity,
+    select,
+    allData = [],
+    title,
+    statusCheck,
+    changeStatus,
+  } = props;
+  const [activeKey, setActiveKey] = useState('1');
+
+  const handleTabsChange = (key) => {
+    setActiveKey(key);
+  };
+
+  const { errorTableData, normalData } = useMemo(() => {
+    let data = { errorTableData: [], normalData: [] };
+    allData?.forEach((item) => {
+      if (item.status == 1 && statusCheck.includes(1)) {
+        data.errorTableData.push(item);
+      } else if (item.status == 0 && statusCheck.includes(0)) {
+        data.normalData.push(item);
+      }
+    });
+    return data;
+  }, [statusCheck, allData]);
+
+  const items = useMemo(() => {
+    let items = [];
+    let showAllTabs = statusCheck.length == 3;
+    if (showAllTabs || errorTableData.length > 0) {
+      items.push({
+        key: '1',
+        label: `异常(${errorTableData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    if (showAllTabs || normalData.length > 0) {
+      items.push({
+        key: '0',
+        label: `正常(${normalData.length || 0})`,
+        children: <div></div>,
+      });
+    }
+    return items;
+  }, [statusCheck, allData]);
+
+  useEffect(() => {
+    if (items.length == 0) {
+      changeStatus(0);
+    } else {
+      setActiveKey(items[0].key);
+      changeStatus(1);
+    }
+  }, [items]);
+
+  if (items.length == 0) return null;
+
+  return (
+    <div className={styles.detailCard}>
+      <div className={styles.tableTop}>
+        {title}
+        <TabsContent
+          active={activeKey}
+          onChange={handleTabsChange}
+          small
+          items={items}
+        ></TabsContent>
+      </div>
+      {activeKey === '1' && (
+        <WaterQualityTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={errorTableData}
+        />
+      )}
+      {activeKey === '0' && (
+        <WaterQualityTable
+          onClickItem={sendMessageToUnity}
+          select={select}
+          items={normalData}
+        />
+      )}
+    </div>
+  );
+}

+ 2 - 2
src/pages/Home/ChemCostComparison.js

@@ -106,7 +106,7 @@ const CostComparison = (props) => {
     });
     if (result && result.length) {
       const [planChemPerCost, actualChemPerCost, planChem, actualChem] = result;
-      const chemPerCost = { yName: 'kg/t' };
+      const chemPerCost = { yName: 'kg/' };
       const chemUsed = { yName: 'kg' };
       chemPerCost.xData = [
         ...new Set(
@@ -277,7 +277,7 @@ const CostComparison = (props) => {
           <div className={styles.item}>
             <div className={styles.value}>
               {open ? topValues.chemPer : '***'}
-              <span className={styles.unit}>kg/t</span>
+              <span className={styles.unit}>kg/</span>
             </div>
             <div className={styles.name}>当月吨水药耗</div>
           </div>

+ 3 - 3
src/pages/Home/EnergyCostComparison.js

@@ -105,7 +105,7 @@ const CostComparison = () => {
     if (result && result.length) {
       const [planElecPerCost, actualElecPerCost, planElecUsed, actualElecUsed] =
         result;
-      const elecPerCost = { yName: 'kWh/t' };
+      const elecPerCost = { yName: 'kwh/m³' };
       const elecUsed = { yName: 'kWh' };
       elecPerCost.xData = [
         ...new Set(
@@ -265,7 +265,7 @@ const CostComparison = () => {
           >
             <div className={styles.value}>
               {open ? curElecPerCost : '***'}
-              <span className={styles.unit}>kWh/t</span>
+              <span className={styles.unit}>kwh/m³</span>
             </div>
             <div className={styles.name}>近一天吨水电耗</div>
           </div>
@@ -289,7 +289,7 @@ const CostComparison = () => {
           >
             <div className={styles.value}>
               {open ? curElecPerCost : '***'}
-              <span className={styles.unit}>kWh/t</span>
+              <span className={styles.unit}>kwh/m³</span>
             </div>
             <div className={styles.name}>当月吨水电耗</div>
           </div>

+ 49 - 32
src/pages/Home/index.js

@@ -4,6 +4,7 @@ import { queryConditionSnapshot } from '@/services/SmartOps';
 import { getToken, UnityAction } from '@/utils/utils';
 import { LoadingOutlined } from '@ant-design/icons';
 import { connect, useParams, useRequest } from '@umijs/max';
+import { Popover } from 'antd';
 import dayjs from 'dayjs';
 import { useEffect, useState } from 'react';
 import { getScadaPage } from '../../services/OperationManagement';
@@ -36,6 +37,7 @@ const HomePage = (props) => {
   useEffect(() => {
     localStorage.width = document.documentElement.getBoundingClientRect().width;
     window.refreshRem();
+    document.body.style.backgroundColor = 'transparent';
   }, []);
   return (
     <div className={styles.content} {...webMouseEvent}>
@@ -224,40 +226,49 @@ const SelfInspection = connect(({ eqSelfInspection, loading }) => ({
 // 能耗监测
 const Electric = (props) => {
   const { data } = props;
-  const { projectId } = useParams();
   const [open, setOpen] = useState(false);
-  const title = (
-    <div
-      onClick={(e) => {
-        e.stopPropagation();
-        setOpen(!open);
-      }}
-    >
-      能耗监测
-      <div
-        style={{ marginLeft: 10 }}
-        className={`password-eye ${open ? 'open' : ''}`}
-      ></div>
+
+  const content = (
+    <div className={styles.popoverContent}>
+      <p>理论值规则:</p>
+      <p>分为高/中/低温3档,</p>
+      <p>高温为≥25℃,低温为<20℃,中温为≥20且<25℃</p>
+      <p>当前温度为近一天平均温度</p>
     </div>
   );
+
   return (
     <div
       className={styles.electric}
       onClick={() => UnityAction.sendMsg('menuItem', '能耗监测')}
     >
-      <Title title={title} />
+      <Title title={'能耗监测'} />
+
+      <div
+        className={`password-eye ${styles.eye} ${open ? 'open' : ''}`}
+        onClick={(e) => {
+          e.stopPropagation();
+          setOpen(!open);
+        }}
+      ></div>
       <ul>
         <li>
           <div className={styles.value}>
             {open ? getValue(data?.elec_unit) : '*****'}
           </div>
-          <div className={styles.btn1}>吨水电耗(KWh/m³)</div>
+          <div className={styles.btn1}>吨水电耗</div>
         </li>
         <li>
           <div className={styles.value}>
-            {open ? getValue(data?.elec) : '*****'}
+            {/* {open ? getValue(data?.elec) : '*****'} */}
+            12312312
           </div>
-          <div className={styles.btn1}>用电量(KWh/h)</div>
+          <Popover title={content}>
+            <div className={styles.btn1} onClick={(e) => e.stopPropagation()}>
+              理论值(KWh/m³)
+              <i className={styles.iconAlert}></i>
+            </div>
+          </Popover>
         </li>
       </ul>
     </div>
@@ -283,33 +294,39 @@ const Medicine = () => {
       return res[0];
     },
   });
-  const title = (
-    <div
-      onClick={(e) => {
-        e.stopPropagation();
-        setOpen(!open);
-      }}
-    >
-      药耗监测
-      <div
-        style={{ marginLeft: 10 }}
-        className={`password-eye ${open ? 'open' : ''}`}
-      ></div>
+  const content = (
+    <div className={styles.popoverContent}>
+      <p>理论值规则:</p>
+      <p>分为高/中/低温3档,</p>
+      <p>高温为≥25℃,低温为<20℃,中温为≥20且<25℃</p>
+      <p>当前温度为近一天平均温度</p>
     </div>
   );
-
   return (
     <div
       className={styles.medicine}
       onClick={() => UnityAction.sendMsg('menuItem', '药耗监测')}
     >
-      <Title title={title} />
+      <Title title={'药耗监测'} />
+
+      <div
+        className={`password-eye ${styles.eye} ${open ? 'open' : ''}`}
+        onClick={(e) => {
+          e.stopPropagation();
+          setOpen(!open);
+        }}
+      ></div>
       <ul>
         <li>
           <div className={styles.valueLong}>
             {open ? data?.value?.toFixed(2) : '*****'}
           </div>
-          <div className={styles.btn1}>当月吨水药成本(元)</div>
+          <Popover title={content}>
+            <div className={styles.btn1} onClick={(e) => e.stopPropagation()}>
+              当月吨水药成本(元)
+              <i className={styles.iconAlert}></i>
+            </div>
+          </Popover>
         </li>
       </ul>
     </div>

+ 23 - 0
src/pages/Home/index.less

@@ -35,6 +35,29 @@
     }
   }
 }
+
+.eye {
+  position: absolute;
+  top: 20px;
+  left: 190px;
+}
+.popoverContent {
+  font-size: 20px;
+  p {
+    margin-bottom: 0;
+    line-height: 36px;
+  }
+}
+.iconAlert {
+  width: 28px;
+  height: 28px;
+  display: block;
+  float: right;
+  margin-top: 5px;
+  margin-left: 6px;
+  background: url('@/assets/home/i.png') no-repeat center;
+  background-size: 100% 100%;
+}
 .smartWork {
   .box;
   width: 604px;

+ 5 - 1
src/pages/Menu/index.js

@@ -1,5 +1,5 @@
 import { UnityAction } from '@/utils/utils';
-import { useState } from 'react';
+import { useEffect, useState } from 'react';
 import styles from './index.less';
 
 const menuList = [
@@ -61,6 +61,10 @@ function Menu() {
     UnityAction.sendMsg('HideMenu');
   };
 
+  useEffect(() => {
+    document.body.style.backgroundColor = 'transparent';
+  }, []);
+
   return (
     <div className={styles.main}>
       <div className={styles.menu}>

+ 81 - 0
src/pages/SafetyManagement/Command/index.js

@@ -0,0 +1,81 @@
+import { checkPW } from '@/services/safety';
+import { UnityAction } from '@/utils/utils';
+import { Modal } from 'antd';
+import md5 from 'md5';
+import { useState } from 'react';
+import styles from './index.less';
+const backIcon = require('@/assets/keyRemove.png');
+
+const CommandModal = () => {
+  const keys = [1, 2, 3, 4, 5, 6, 7, 8, 9, '清空', 0, 12];
+  const [values, setValues] = useState([]);
+
+  const handlerClick = (key) => {
+    if (key == 12) {
+      const newValues = [...values];
+      setValues(newValues.splice(0, values.length - 1));
+    } else if (key == '清空') {
+      setValues([]);
+    } else {
+      const newValues = [...values, key];
+      setValues(newValues);
+      if (newValues.length == 8) handleCheckPw(newValues.join(''));
+    }
+  };
+  const handleCheckPw = async (value) => {
+    const pw = md5(value);
+    const res = await checkPW({ pw });
+    if (res) {
+      UnityAction.sendMsg();
+      // message.success('已切换成【控制模式】');
+    }
+  };
+  return (
+    <div className={styles.modelMain}>
+      <Modal
+        title="请输入口令"
+        cancelText="取消"
+        okText="确定"
+        width={640}
+        open={true}
+        footer={null}
+        closable={false}
+      >
+        <div className={styles.upContent}>
+          {new Array(8).fill('').map((item, idx) => (
+            <div className={styles.upItem}>{values[idx]}</div>
+          ))}
+        </div>
+        <div className={styles.numContent}>
+          {keys.map((item) => {
+            let comment = <div></div>;
+            if (item == 12) {
+              comment = (
+                <div
+                  className={styles.numberItem}
+                  onClick={() => handlerClick(item)}
+                >
+                  <img src={backIcon} />
+                </div>
+              );
+            } else {
+              comment = (
+                <div
+                  className={`${styles.numberItem} ${
+                    item == '清空' ? styles.remove : ''
+                  }`}
+                  onClick={() => handlerClick(item)}
+                >
+                  {item}
+                </div>
+              );
+            }
+            return comment;
+          })}
+        </div>
+      </Modal>
+    </div>
+  );
+};
+
+export default CommandModal;

+ 44 - 0
src/pages/SafetyManagement/Command/index.less

@@ -0,0 +1,44 @@
+.upContent {
+  display: flex;
+  margin-left: 4px;
+  margin-bottom: 20px;
+  width: 100%;
+  .upItem {
+    text-align: center;
+    line-height: 54px;
+    font-size: 26px;
+    margin-right: 10px;
+    width: 64px;
+    height: 64px;
+    background: #ffffff;
+    box-shadow: 0px 0px 8px 3px rgba(204, 204, 204, 0.5);
+  }
+}
+.numContent {
+  display: flex;
+  flex-wrap: wrap;
+}
+.numberItem {
+  width: 33%;
+  height: 90px;
+  font-size: 28px;
+  user-select: none;
+  font-weight: bold;
+  line-height: 90px;
+  text-align: center;
+  border: 1px solid rgba(128, 128, 128, 0.592);
+}
+.remove {
+  .numberItem;
+  font-size: 24px;
+}
+
+:global {
+  .ant-modal-title {
+    font-size: 28px;
+    line-height: 28px;
+  }
+  .ant-modal-close-x {
+    font-size: 28px;
+  }
+}

+ 6 - 0
src/services/safety.js

@@ -17,3 +17,9 @@ export async function queryMonitorList(projectId) {
 export async function queryMonitorOnlineCount(projectId) {
   return request(`/api/v1/monitor/online_count/${projectId}`);
 }
+export const checkPW = async (data) => {
+  return await request(`/api/v1/user/check_automationPw`, {
+    method: 'POST',
+    body: data,
+  });
+};

Some files were not shown because too many files changed in this diff