Browse Source

无人值守优化

Renxy 1 year ago
parent
commit
a7c722f887

+ 20 - 2
.umirc.ts

@@ -204,15 +204,33 @@ export default defineConfig({
     // 操作记录
     {
       name: '',
-      path: '/smart-ops/operation-record/:projectId', ///safety management
+      path: '/smart-ops/operation-record/:projectId',
       component: './SmartOps/OperationRecord',
     },
     // 图标弹窗页面
     {
       name: '',
-      path: '/smart-ops/chart-page/:projectId', ///safety management
+      path: '/smart-ops/chart-page/:projectId',
       component: './SmartOps/ChartPage',
     },
+    // 系统工作日报
+    {
+      name: '',
+      path: '/system-daily/:projectId',
+      component: './SystemDaily/index',
+    },
+    //个人中心
+    {
+      name: '',
+      path: '/center/:projectId',
+      component: './Center/index',
+    },
+    //智慧运营报告
+    {
+      name: '',
+      path: '/smart-report/:projectId',
+      component: './SmartReport/index',
+    },
   ],
   npmClient: 'yarn',
 });

BIN
src/assets/center/profile.png


+ 36 - 0
src/pages/Center/index.js

@@ -0,0 +1,36 @@
+import { useNavigate, useParams } from '@umijs/max';
+import styles from './index.less';
+const Center = () => {
+  const navigate = useNavigate();
+  const { projectId } = useParams();
+
+  const handleGoSystem = () => {
+    navigate(`/system-daily/${projectId}`);
+  };
+
+  return (
+    <div className={styles.page}>
+      <div className={styles.head}>
+        <div className={styles.profile} />
+        <div className={styles.textContent}>
+          <div className={styles.name}>张晓丽</div>
+          <div className={styles.photo}>手机号:13576970 系统版本:v1.0.47</div>
+        </div>
+      </div>
+      <div className={styles.center}>
+        <div className={styles.item}>我的任务</div>
+        <div className={styles.item}>我的工单</div>
+      </div>
+      <div className={styles.bottomContent}>
+        <div className={styles.lineItem} onClick={handleGoSystem}>
+          系统报告
+        </div>
+        <div className={styles.lineItem}>智慧运用报告</div>
+        <div className={styles.lineItem}>问题反馈备份</div>
+        <div className={styles.lineItem}>个人设置</div>
+      </div>
+      <div className={styles.loginOut}>退出登录</div>
+    </div>
+  );
+};
+export default Center;

+ 87 - 0
src/pages/Center/index.less

@@ -0,0 +1,87 @@
+.page {
+  margin: auto;
+  width: 80%;
+}
+.box {
+  background: rgba(255, 255, 255, 0.78);
+  box-shadow: 0px 0px 8px 4px rgba(212, 212, 212, 0.5);
+  border-radius: 20px;
+  opacity: 0.8;
+}
+.head {
+  .box;
+  margin-bottom: 30px;
+  padding: 64px 76px;
+  display: flex;
+  .profile {
+    width: 150px;
+    height: 150px;
+    background-image: url('@/assets/center/profile.png');
+    background-size: 100%, 100%;
+  }
+  .textContent {
+    margin-left: 60px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+    .name {
+      font-size: 34px;
+      font-family: PingFangSC, PingFang SC;
+      font-weight: 400;
+      color: #4a4a4a;
+      line-height: 48px;
+    }
+    .photo {
+      font-size: 28px;
+      font-family: PingFangSC, PingFang SC;
+      font-weight: 400;
+      color: #4a4a4a;
+      line-height: 40px;
+    }
+  }
+}
+.center {
+  margin-bottom: 30px;
+  height: 150px;
+  display: flex;
+  justify-content: space-between;
+  .item {
+    .box;
+    width: 49%;
+    text-align: center;
+    font-size: 32px;
+    line-height: 150px;
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 400;
+    color: #4a4a4a;
+  }
+}
+.bottomContent {
+  .box;
+  padding: 10px 30px;
+  font-size: 32px;
+  font-family: PingFangSC, PingFang SC;
+  font-weight: 400;
+  color: #4a4a4a;
+  .lineItem {
+    height: 100px;
+    line-height: 100px;
+    border-bottom: 1px solid #d4d4d4;
+  }
+  .lineItem:last-child {
+    border-bottom: none;
+  }
+}
+.loginOut {
+  margin: 50px auto 0;
+  width: 329px;
+  height: 97px;
+  text-align: center;
+  background: rgba(74, 144, 226, 0.85);
+  border-radius: 49px;
+  font-size: 32px;
+  font-family: PingFangSC, PingFang SC;
+  font-weight: 400;
+  color: #ffffff;
+  line-height: 97px;
+}

+ 0 - 0
src/pages/Home/backlog.js


+ 47 - 5
src/pages/Home/index.js

@@ -1,3 +1,4 @@
+import { getPendingList } from '@/services/message';
 import { getComparisonData } from '@/services/OperationManagement';
 import { queryConditionSnapshot } from '@/services/SmartOps';
 import { getToken, UnityAction } from '@/utils/utils';
@@ -18,7 +19,7 @@ const HomePage = (props) => {
   return (
     <div className={styles.content}>
       <LeftContent data={data} />
-      <CenterContent />
+      {/* <CenterContent /> */}
       <RightContent data={data} />
     </div>
   );
@@ -31,6 +32,7 @@ const LeftContent = (props) => {
       <SmartWork data={data} />
       <WaterAmt data={data} />
       <WaterQuality data={data} />
+      <Backlog />
     </div>
   );
 };
@@ -48,6 +50,7 @@ const RightContent = (props) => {
       <SelfInspection />
       <Electric data={data} />
       <Medicine />
+      <Scada />
     </div>
   );
 };
@@ -230,24 +233,63 @@ const Scada = () => {
         (item) =>
           `${domain}smart-water/scada/index.html#/3dview/${projectId}/${item.id}?JWT-TOKEN=${token}&hideTitle=true`,
       );
-      return urls.splice(0, 2);
+      console.log('-------------------', urls);
+      return urls.splice(0, 1);
     },
   });
   return (
     <Box
-      big
       title="工艺监控"
       onClick={() => UnityAction.sendMsg('menuItem', '工艺监控')}
     >
-      <div className={styles.scadaContent}>
+      <div className={styles.scada}>
         {data?.map((url) => (
-          <iframe src={url} />
+          <iframe style={{ width: '450px', height: '270px' }} src={url} />
         ))}
       </div>
     </Box>
   );
 };
 
+// 能耗监测
+const Backlog = (props) => {
+  // const { data } = props;
+  const { projectId } = useParams();
+
+  const { data, loading } = useRequest(getPendingList, {
+    defaultParams: [{ project_id: projectId }],
+  });
+  console.log(data);
+  const handleClick = () => {
+    //TODO
+  };
+  return (
+    <Box
+      title={
+        <div style={{ display: 'flex' }}>
+          待办事项
+          <div className={styles.count}>{data?.length || 0}</div>
+        </div>
+      }
+      onClick={() => UnityAction.sendMsg('menuItem', '待办事项')}
+    >
+      <div className={styles.backlog}>
+        <div>
+          {data?.map((item) => (
+            <>
+              <div className={styles.createTime}>{item.time}</div>
+              <div className={styles.item} onClick={() => handleClick(item)}>
+                <div className={styles.point} />
+                {item.title}
+              </div>
+            </>
+          ))}
+        </div>
+      </div>
+    </Box>
+  );
+};
+
 const Box = ({ title, children, onClick, big }) => {
   return (
     <div

+ 34 - 2
src/pages/Home/index.less

@@ -53,7 +53,10 @@
 }
 .boxBig {
   .box;
-  background-image:  url('@/assets/home-box-bg2.png');
+  background-image: url('@/assets/home-box-bg2.png');
+}
+.scada {
+  padding: 0 10px;
 }
 .scadaContent {
   padding: 20px;
@@ -121,4 +124,33 @@
   .box {
     width: 100%;
   }
-}
+}
+.backlog {
+  padding: 0 10px;
+  overflow-y: auto;
+  height: 200px;
+
+  .createTime {
+  }
+  .item {
+    margin: 4px 0 10px;
+    width: 100%;
+    height: 50px;
+    background-color: #346194;
+    line-height: 50px;
+  }
+  .point {
+    margin: 0 10px;
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    border-radius: 50%;
+    background-color: yellow;
+  }
+}
+.count {
+  background: #f69040;
+  border-radius: 4px;
+  margin-left: 10px;
+  padding: 0 6px;
+}

+ 168 - 0
src/pages/SmartOps/components/DeviceAnalysis.js

@@ -0,0 +1,168 @@
+import TabsContent from '@/components/TabsContent';
+import { UnityAction } from '@/utils/utils';
+import { connect } from '@umijs/max';
+import { Spin, Table, Tabs } from 'antd';
+import { useEffect, useMemo, useState } from 'react';
+import styles from './DeviceAnalysis.less';
+import ThresholdBar from './ThresholdBar';
+const { TabPane } = Tabs;
+
+const DeviceAnalysis = (props) => {
+  const Status = [
+    { name: '异常', type: '1', data: [] },
+    { name: '全部', type: '2', data: [] },
+  ];
+
+  const { list = [], processList, loading } = props;
+  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
+  const [tab, setTab] = useState('1');
+
+  const columns = [
+    {
+      title: '设备名称',
+      width: '20%',
+      render: (record) => (
+        <div>
+          {record.DeviceName}({record.DeviceCode})
+        </div>
+      ),
+    },
+    {
+      title: '巡检项',
+      width: '14%',
+      dataIndex: 'ProcessSectionId',
+      render: (id) => {
+        return processList.find((item) => item.id == id)?.name;
+      },
+    },
+    {
+      title: '设定值范围',
+      width: '14%',
+      render: (record) => {
+        let thresholds = record.fault_range.split(',');
+        return (
+          <div>
+            {record.fault_range && (
+              <ThresholdBar
+                current={record.fault_result}
+                thresholds={thresholds}
+              />
+            )}
+          </div>
+        );
+      },
+    },
+    {
+      title: '状态',
+      width: '20%',
+      dataIndex: 'Reason',
+    },
+  ];
+
+  useEffect(() => {
+    UnityAction.on('SynDev', selectedItem);
+    return () => UnityAction.off('SynDev', selectedItem);
+  }, [data, tab]);
+
+  const selectedItem = (e) => {
+    setSelectedRowKeys([e]);
+    console.log(data);
+    const itemIndex = data?.findIndex((item) => item.type == tab);
+    const index = data[itemIndex]?.data?.findIndex(
+      (item) => item.DeviceCode == e,
+    );
+    if (index !== 0 || index != -1) {
+      const dom = document.querySelector(`tr[data-row-key="${index}"]`);
+      if (dom) {
+        let v = document.getElementsByClassName('ant-table-body')[itemIndex];
+        v.scrollTop = dom.offsetTop;
+      }
+    }
+  };
+
+  const data = useMemo(() => {
+    return Status.map((item, idx) => {
+      const data = list?.filter((cur) => cur.grade_alarm == item.type);
+      return { ...item, data };
+    });
+  }, [list]);
+
+  const handleBtnClick = (plcs, title) => {
+    if (!plcs) return;
+    const msg = JSON.stringify(plcs); //[{ dataitemid: 'Raw_Water_Tank_Level', deviceid: '1436022785' }]
+    UnityAction.sendMsg(
+      'ProcessAnalysisAbout',
+      JSON.stringify({
+        title,
+        data: msg,
+      }),
+    );
+  };
+
+  const onTabChange = (tab) => {
+    setTab(tab);
+    UnityAction.sendMsg('ProcessAnalysisType', tab);
+  };
+
+  const rowSelection = {
+    type: 'radio',
+    selectedRowKeys,
+    onChange: (selectedRowKeys, selectedRows) => {
+      setSelectedRowKeys(selectedRowKeys);
+      UnityAction.sendMsg('SynDev', selectedRows[0].DeviceCode);
+    },
+  };
+
+  const onSelectRow = (record, index) => {
+    const selectedList = [...selectedRowKeys];
+    if (selectedList[0] === index) return;
+    selectedList[0] = index;
+    setSelectedRowKeys(selectedList);
+    UnityAction.sendMsg('SynDev', record.DeviceCode);
+  };
+
+  const setRowClassName = (record, index) => {
+    return index === selectedRowKeys[0] ||
+      record.DeviceCode == selectedRowKeys[0]
+      ? styles.tableSelect
+      : '';
+  };
+
+  return (
+    <Spin spinning={loading}>
+      <div className="card-box">
+        <TabsContent
+          small={true}
+          center={false}
+          defaultActiveKey="1"
+          items={data?.map((item) => {
+            return {
+              label: `${item.name}(${item.data?.length || 0})`,
+              key: item.type,
+              children: (
+                <Table
+                  dataSource={item.data}
+                  columns={columns}
+                  // rowKey={'DeviceCode'}
+                  // rowSelection={rowSelection}
+                  rowClassName={setRowClassName}
+                  onRow={(record, index) => ({
+                    onClick: () => onSelectRow(record, index),
+                  })}
+                  pagination={false}
+                  scroll={{ y: document.body.clientHeight - 730 }}
+                />
+              ),
+            };
+          })}
+          onChange={onTabChange}
+        />
+      </div>
+    </Spin>
+  );
+};
+export default connect(({ smartOps, loading }) => ({
+  loading: loading.effects['smartOps/queryList'],
+  list: smartOps.list.list,
+  processList: smartOps.processList,
+}))(DeviceAnalysis);

+ 3 - 0
src/pages/SmartOps/components/DeviceAnalysis.less

@@ -0,0 +1,3 @@
+.tableSelect {
+  background: rgba(145, 192, 238, 0.16) !important;
+}

+ 62 - 51
src/pages/SmartOps/components/VideoAnalysis.js

@@ -1,6 +1,7 @@
 import { UnityAction } from '@/utils/utils';
 import { Collapse, Empty, Spin, Tabs } from 'antd';
 import { useEffect, useState } from 'react';
+import ThresholdBar from './ThresholdBar';
 import styles from './VideoAnalysis.less';
 
 const { TabPane } = Tabs;
@@ -54,7 +55,9 @@ function VideoAnalysis(props) {
                     ? styles.tableSelect
                     : styles.table
                 }
-                expandIconPosition="right"
+                expandIcon={() => (
+                  <div className={styles.typeText}>视频报警</div>
+                )}
                 onChange={(e) => {
                   handleCollapse(item.id);
                 }}
@@ -68,25 +71,6 @@ function VideoAnalysis(props) {
         ) : (
           <Empty />
         )}
-        {/* {data?.list?.map(item => (
-          <Collapse
-            defaultActiveKey={[item.id]}
-            key={item.id}
-            className={
-              selectedName == item.device_name || prevKey == item.id
-                ? styles.tableSelect
-                : styles.table
-            }
-            expandIconPosition="right"
-            onChange={e => {
-              handleCollapse(item.id);
-            }}
-          >
-            <Panel header={item.device_name} key={item.id}>
-              <AnalysisContent item={item} />
-            </Panel>
-          </Collapse>
-        ))} */}
       </div>
     </Spin>
   );
@@ -98,43 +82,70 @@ function AnalysisContent({ item }) {
     UnityAction.sendMsg('SensorPic');
   };
 
+  const renderContent = (key, item) => {
+    let content = '';
+    switch (key) {
+      case 1:
+        content = (
+          <>
+            <div className={styles.label}>画面报警:</div>
+            <div className={styles.content}>
+              {item.event_type}
+              <img
+                className={styles.img}
+                src={item.url}
+                onClick={handleImgClick}
+              />
+            </div>
+          </>
+        );
+        break;
+      case 2:
+        content = (
+          <>
+            <div className={styles.contentFlex}>
+              <div>参数:温度</div>
+              <div className={styles.threshold}>
+                <span>阈值范围:</span>
+                <div style={{ width: '180px' }}>
+                  <ThresholdBar current={0.5} thresholds={[0, 1]} />
+                </div>
+              </div>
+
+              <div>
+                状态:<span className={styles.textAbnormal}>异常</span>
+              </div>
+            </div>
+          </>
+        );
+        break;
+      case 3:
+        content = (
+          <>
+            <div className={styles.contentFlex}>
+              <div>原液位:12.01</div>
+              <div> 仪表液位:12.12 </div>
+
+              <div>
+                状态:<span className={styles.textAbnormal}>异常</span>
+              </div>
+            </div>
+          </>
+        );
+        break;
+    }
+    return content;
+  };
+
   return (
     <div className={styles.box}>
-      {/* <div className={styles.item} style={{ width: '48%' }}>
-        <div className={styles.label} style={{ lineHeight: '66px' }}>
-          温度数据:
-        </div>
-        <div className={styles.content}>
-          <NewNumberBar breakdown={breakdown} exception={exception} current={0.05} scale />
-        </div>
-      </div>
-      <div className={styles.item} style={{ width: '48%' }}>
-        <div className={styles.label} style={{ lineHeight: '66px' }}>
-          噪音数据:
-        </div>
-        <div className={styles.content}>
-          <NewNumberBar breakdown={breakdown} exception={exception} current={0.05} scale />
-        </div>
-      </div> */}
       <div className={styles.item}>
-        <div className={styles.label}>画面报警:</div>
-        <div className={styles.content}>
+        {renderContent(3, item)}
+        {/* <div className={styles.content}>
           {item.event_type}
           <img className={styles.img} src={item.url} onClick={handleImgClick} />
-        </div>
+        </div> */}
       </div>
-      {/* <div className={styles.item}>
-        <div className={styles.label}>可能原因:</div>
-        <div className={styles.content}>
-          建议调整杀菌周期为27分,下调10.00%建议调整杀菌周期为27分,下调10.00%建议调整杀菌周期为27分,下调10.00%建议调整杀菌周期为27分,下调10.00%
-        </div>
-      </div>
-      <div className={styles.item}>
-        <div className={styles.label}>解决方案:</div>
-        <div className={styles.content}>
-          建议调整杀菌周期为27分,下调10.00%建议调整杀菌周期为27分,下调10.00%建议调整杀菌周期为27分,下调10.00%建议调整杀菌周期为27分,下调10.00%
-        </div>
-      </div> */}
     </div>
   );
 }

+ 27 - 6
src/pages/SmartOps/components/VideoAnalysis.less

@@ -9,7 +9,7 @@
     align-items: flex-start;
     font-size: 22px;
     line-height: 28px;
-    color: #fff;
+    color: #454444;
     .label {
       width: 114px;
       flex-shrink: 0;
@@ -17,6 +17,12 @@
     .content {
       flex: 1;
     }
+    .contentFlex {
+      width: 100%;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
   }
 }
 
@@ -33,23 +39,38 @@
   .table {
     background-color: #064779;
   }
+  .typeText {
+    color: #4a90e2 !important;
+  }
+  .threshold {
+    display: flex;
+    align-items: center;
+  }
+  .textAbnormal {
+    color: #fe5850;
+  }
+  .textNormal {
+    color: #4a90e2;
+  }
 
   :global {
     .ant-collapse > .ant-collapse-item {
-      border: 1px solid #329bfe;
-      // background: #2466a4;
+      border-radius: 8px;
+      box-shadow: 0px 0px 8px 2px rgba(191, 191, 191, 0.2);
+      border: 1px solid #eee;
+      background: rgba(255, 255, 255);
       padding: 0 15px;
       margin-bottom: 15px;
-      border-radius: 5px;
       &.ant-collapse-item-active > .ant-collapse-header {
         border-bottom: 1px solid #7a9dcd;
       }
       > .ant-collapse-header {
         background: none;
-        color: #fff;
+        color: rgb(91, 88, 88) 373;
         height: 62px;
         font-size: 22px;
         padding: 0;
+        align-items: center;
         border-bottom: 1px solid transparent;
         .ant-collapse-arrow {
           font-size: 22px;
@@ -62,7 +83,7 @@
       }
     }
     .ant-collapse:last-child > .ant-collapse-item {
-      margin-bottom: 0;
+      // margin-bottom: 0;
     }
     .ant-collapse-content {
       padding: 15px 0;

+ 7 - 11
src/pages/SmartOps/index.js

@@ -19,6 +19,7 @@ import { Tabs } from 'antd';
 import dayjs from 'dayjs';
 import { useEffect, useMemo, useRef, useState } from 'react';
 import Analysis from './Analysis';
+import DeviceAnalysis from './components/DeviceAnalysis';
 import VideoAnalysis from './components/VideoAnalysis';
 import WorkAnalysis from './components/WorkAnalysis';
 import styles from './index.less';
@@ -37,7 +38,6 @@ function SmartOps(props) {
   const [searchParams, setSearchParams] = useSearchParams();
   const time = searchParams.get('time');
   const idList = searchParams.get('idList');
-  console.log('-------------------', time, idList);
 
   // const [eTime, setETime] = useState(time ? time : dayjs().format('YYYY-MM-DD HH:mm:ss'));
   // const [sTime, setSTime] = useState(
@@ -165,7 +165,7 @@ function SmartOps(props) {
   const { run, loading: loadingVideo } = useRequest(
     () =>
       getCameraList(projectId, {
-        s_time: sTime,
+        s_time: dayjs().subtract(10, 'month').format('YYYY-MM-DD HH:mm:ss'), //sTime,
         e_time: eTime,
         pageSize: 999,
       }),
@@ -276,15 +276,6 @@ function SmartOps(props) {
   return (
     <PageContent>
       <PageTitle returnable={time}>智慧分析</PageTitle>
-      {/* {time && (
-        <Button
-          type="primary"
-          style={{ marginBottom: 20 }}
-          onClick={() => navigate(-1)}
-        >
-          返回
-        </Button>
-      )} */}
       <div className={`card-box ${styles.topContent}`}>
         <div className={styles.titleContent}>
           <span className={styles.time}>{showTime}</span>
@@ -339,6 +330,11 @@ function SmartOps(props) {
                 />
               ),
             },
+            {
+              label: `设备分析(${loading ? '-' : AnalysisNumber})`,
+              key: '4',
+              children: <DeviceAnalysis />,
+            },
             {
               label: `工艺分析(${loading ? '-' : AnalysisNumber})`,
               key: '2',

+ 0 - 2
src/pages/SmartOps/models/smartOps.js

@@ -30,7 +30,6 @@ export default {
         const response = yield call(queryListNew, payload);
         if (response) {
           response?.data?.list?.map((item) => {
-            console.log('--------------------------', analysisDict);
             var reason = analysisDict?.data?.find(
               (reason) => reason.id == item.Reason,
             );
@@ -46,7 +45,6 @@ export default {
                 );
                 if (fixPlan) item.FixPlan.push(fixPlan);
               });
-              console.log(item.FixPlan);
             }
           });
           yield put({

+ 96 - 0
src/pages/SmartReport/index.js

@@ -0,0 +1,96 @@
+import ModuleTitle from '@/components/ManagementPage/moduleTitle';
+import { useNavigate, useParams } from '@umijs/max';
+import styles from './index.less';
+const SmartReport = () => {
+  const navigate = useNavigate();
+  const { projectId } = useParams();
+
+  return (
+    <div className={styles.page}>
+      <div className={styles.head}>
+        <div>
+          <div className={styles.name}>智慧运营报告</div>
+          <div className={styles.photo}>11月9日-11月15日</div>
+        </div>
+        <div>时间:</div>
+      </div>
+      <div className={styles.box}>
+        <div className={styles.left}>概览</div>
+        <div className={styles.title}>无锡锡山水厂</div>
+        <div className={styles.content}>
+          <div className={styles.item}>智慧运营天数:2732天</div>
+          <div className={styles.item}>智慧运营天数:2732天</div>
+          <div className={styles.item}>智慧运营天数:2732天</div>
+          <div className={styles.item}>智慧运营天数:2732天</div>
+          <div className={styles.item}>智慧运营天数:2732天</div>
+          <div className={styles.item}>智慧运营天数:2732天</div>
+          <div className={styles.item}>智慧运营天数:2732天</div>
+          <div className={styles.item}>智慧运营天数:2732天</div>
+        </div>
+      </div>
+      <div className={styles.box}>
+        <ModuleTitle title="水量" />
+        <div className={styles.content}>
+          <div className={styles.item}>累积进水:12343t</div>
+          <div className={styles.item}>累积出水:12232t</div>
+        </div>
+      </div>
+      <div className={styles.box}>
+        <ModuleTitle title="能耗" />
+        <div className={styles.content}>
+          <div className={styles.item}>吨水电耗:122kwh</div>
+          <div className={styles.item}>累积耗电量:12</div>
+        </div>
+      </div>
+      <div className={styles.box}>
+        <ModuleTitle title="药耗" />
+        <div className={styles.content}>
+          <div className={styles.item}>吨水药耗:12</div>
+          <div className={styles.item}>累积用药量:122kwh</div>
+        </div>
+      </div>
+      <div className={styles.box}>
+        <ModuleTitle title="系统自检" />
+        <div className={styles.threeContent}>
+          <div className={styles.numItem}>
+            <div>12333</div>
+            <div>自检次数</div>
+          </div>
+          <div className={styles.numItem}>
+            <div>12333</div>
+            <div>自检次数</div>
+          </div>
+          <div className={styles.numItem}>
+            <div>12333</div>
+            <div>自检次数</div>
+          </div>
+        </div>
+        <div>异常类型统计(设备异常、工艺异常、安全隐患异常)</div>
+      </div>
+      <div className={styles.box}>
+        <ModuleTitle title="智慧运营" />
+        <div className={styles.smartText}>智慧运营本周累计节省金额:234元</div>
+        <div className={styles.smartText}>累积用药量:122kwh</div>
+      </div>
+      <div className={styles.box}>
+        <ModuleTitle title="任务工单" />
+        <div className={styles.content}>
+          <div className={styles.item}>任务数量:1234</div>
+          <div className={styles.item}>工单数量:234</div>
+          <div className={styles.item}>任务数量:1234</div>
+          <div className={styles.item}>工单数量:234</div>
+          <div className={styles.item}>任务数量:1234</div>
+          <div className={styles.item}>工单数量:234</div>
+        </div>
+      </div>
+      <div className={styles.box}>
+        <ModuleTitle title="设备维修保养" />
+        <div className={styles.content}>
+          <div className={styles.item}>维修数量:12</div>
+          <div className={styles.item}>保养数量:12</div>
+        </div>
+      </div>
+    </div>
+  );
+};
+export default SmartReport;

+ 80 - 0
src/pages/SmartReport/index.less

@@ -0,0 +1,80 @@
+.page {
+  margin: auto;
+  padding: 0 100px 100px;
+  width: 80%;
+  background: rgba(255, 255, 255, 0.78);
+  box-shadow: 0px 0px 8px 4px rgba(212, 212, 212, 0.5);
+  border-radius: 20px;
+  opacity: 0.8;
+  font-size: 30px;
+  font-weight: 400;
+  color: #4a4a4a;
+}
+.name {
+  font-size: 34px;
+  font-family: PingFangSC, PingFang SC;
+  font-weight: 400;
+  color: #4a4a4a;
+  line-height: 48px;
+}
+
+.head {
+  padding: 48px 0;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+
+  .time {
+    font-size: 22px;
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 400;
+    color: #4a4a4a;
+    line-height: 40px;
+  }
+}
+.box {
+  margin: 24px 0;
+  padding: 38px 30px;
+  background-color: #e7f1fe;
+  .title {
+    .name;
+    width: 100%;
+    text-align: center;
+  }
+  .left {
+    position: relative;
+    left: 20px;
+    float: left;
+    font-size: 30px;
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 400;
+    color: #4a4a4a;
+    line-height: 42px;
+  }
+  .content {
+    display: flex;
+    padding: 20px;
+    flex-wrap: wrap;
+    .item {
+      width: 50%;
+      margin-bottom: 18px;
+      font-size: 30px;
+      font-family: PingFangSC, PingFang SC;
+      font-weight: 400;
+      color: #4a4a4a;
+      line-height: 42px;
+    }
+  }
+  .threeContent {
+    display: flex;
+    padding: 20px;
+    justify-content: space-around;
+    .numItem {
+      .left;
+      text-align: center;
+    }
+  }
+  .smartText {
+    margin-bottom: 18px;
+  }
+}

+ 23 - 0
src/pages/SystemDaily/index.js

@@ -0,0 +1,23 @@
+import PageContent from '@/components/PageContent';
+import styles from './index.less';
+const SystemDaily = () => {
+  return (
+    <PageContent>
+      <div className={styles.main}>
+        <div className={styles.titleContent}>
+          <div className={styles.title}>系统工作日报</div>
+          <div className={styles.time}>11月15日</div>
+        </div>
+        <div className={styles.content}>
+          <div className={styles.text}>执行自控指令次数:12次</div>
+          <div className={styles.text}>执行自控指令次数:12次</div>
+          <div className={styles.text}>执行自控指令次数:12次</div>
+          <div className={styles.text}>执行自控指令次数:12次</div>
+          <div className={styles.text}>执行自控指令次数:12次</div>
+          <div className={styles.text}>执行自控指令次数:12次</div>
+        </div>
+      </div>
+    </PageContent>
+  );
+};
+export default SystemDaily;

+ 40 - 0
src/pages/SystemDaily/index.less

@@ -0,0 +1,40 @@
+.main {
+  padding: 50px;
+  width: 80%;
+  margin: 60px auto;
+  background-color: #ffffff;
+  background: rgba(255, 255, 255, 0.78);
+  box-shadow: 0px 0px 8px 4px rgba(212, 212, 212, 0.5);
+  border-radius: 20px;
+  opacity: 0.8;
+}
+.titleContent {
+  width: 100%;
+  text-align: center;
+  font-family: PingFangSC, PingFang SC;
+  color: #4a4a4a;
+  margin: auto;
+  .title {
+    font-size: 34px;
+    line-height: 48px;
+  }
+  .time {
+    font-size: 22px;
+    line-height: 30px;
+  }
+}
+.content {
+  padding: 60px 30px;
+  margin: 20px auto;
+  width: 80%;
+  box-shadow: 0px 0px 8px 4px rgba(212, 212, 212, 0.5);
+  border-radius: 20px;
+  opacity: 0.8;
+  background: #e7f1fe;
+  .text {
+    margin-bottom: 34px;
+    font-family: PingFangSC, PingFang SC;
+    color: #4a4a4a;
+    font-size: 30px;
+  }
+}

+ 3 - 3
src/services/dumu.js

@@ -39,17 +39,17 @@ export async function getHistoryList(projectId, params) {
   res.data.list.forEach((item) => {
     item.url = base64ToImageUrl(item.event_bg);
   });
-  return res.data.list;
+  return { data: res.data.list };
 }
 
 export async function getCameraList(projectId, params) {
   const res = await request(
     `/api/v1/dumu/list/${projectId}?${stringify(params)}`,
   );
-  return res.data;
+  return res;
 }
 
 export async function getDetail(detailId, options) {
   const res = await request(`/api/v1/dumu/detail/${detailId}`, options);
-  return res.data;
+  return res;
 }

+ 9 - 0
src/services/message.js

@@ -10,3 +10,12 @@ import { request } from 'umi';
 export async function getNotificationList(params) {
   return request(`/api/v1/notification/list?${stringify(params)}`);
 }
+
+/**
+ * 待办事项
+ * @param {object} project_id
+ * @returns
+ */
+export async function getPendingList(params) {
+  return request(`/api/v1/pending/list?${stringify(params)}`);
+}