Quellcode durchsuchen

feat(分屏展示): 添加左侧树

xieyonghong vor 3 Jahren
Ursprung
Commit
1841c7da89

+ 1 - 1
src/components/Player/index.less

@@ -60,7 +60,7 @@
   }
 
   .live-player-tools {
-    flex-basis: 290px;
+    flex-basis: 288px;
     padding: 50px 12px 0 40px;
 
     .direction {

+ 46 - 5
src/pages/media/Device/Channel/Tree/index.tsx

@@ -1,23 +1,48 @@
 import { Tree, Input } from 'antd';
 import { useRequest } from 'umi';
 import { service } from '../index';
-import { useEffect } from 'react';
+import React, { useEffect, useState } from 'react';
 import './index.less';
 import { SearchOutlined } from '@ant-design/icons';
 
 interface TreeProps {
   deviceId: string;
+  onSelect: (id: React.Key) => void;
 }
 
 export default (props: TreeProps) => {
-  const { data: TreeData, run: getTreeData } = useRequest(service.queryTree, {
+  const [treeData, setTreeData] = useState<any>([]);
+  const [selectedKeys, setSelectedKeys] = useState<React.Key[]>(['']);
+  const { run: getTreeData } = useRequest(service.queryTree, {
     manual: true,
-    formatResult: (res) => res.result,
+    onSuccess: (res) => {
+      treeData[0].children = res.result;
+      setTreeData(treeData);
+    },
   });
 
+  /**
+   * 获取设备详情
+   * @param id
+   */
+  const getDeviceDetail = async (id: string) => {
+    const deviceResp = await service.deviceDetail(id);
+    if (deviceResp.status === 200) {
+      setTreeData([
+        {
+          id,
+          name: deviceResp.result.name,
+          children: [],
+        },
+      ]);
+      setSelectedKeys([id]);
+      getTreeData(props.deviceId, {});
+    }
+  };
+
   useEffect(() => {
     if (props.deviceId) {
-      getTreeData(props.deviceId, {});
+      getDeviceDetail(props.deviceId);
     }
   }, [props.deviceId]);
 
@@ -27,7 +52,23 @@ export default (props: TreeProps) => {
         <Input placeholder={'请输入目录名称'} suffix={<SearchOutlined />} />
       </div>
       <div className={'channel-tree-content'}>
-        <Tree height={500} treeData={TreeData} />
+        <Tree
+          height={500}
+          selectedKeys={selectedKeys}
+          treeData={treeData}
+          onSelect={(keys) => {
+            if (keys.length) {
+              setSelectedKeys(keys);
+              if (props.onSelect) {
+                props.onSelect(keys[0]);
+              }
+            }
+          }}
+          fieldNames={{
+            key: 'id',
+            title: 'name',
+          }}
+        />
       </div>
     </div>
   );

+ 17 - 1
src/pages/media/Device/Channel/index.tsx

@@ -182,7 +182,23 @@ export default () => {
     <PageContainer>
       <div className={'device-channel-warp'}>
         <div className={'left'}>
-          <Tree deviceId={deviceId} />
+          <Tree
+            deviceId={deviceId}
+            onSelect={(key) => {
+              if (key === deviceId && actionRef.current?.reset) {
+                actionRef.current?.reset();
+              } else {
+                setQueryParam({
+                  terms: [
+                    {
+                      column: 'parentId',
+                      value: key,
+                    },
+                  ],
+                });
+              }
+            }}
+          />
         </div>
         <div className={'right'}>
           <SearchComponent field={columns} onSearch={searchFn} />

+ 3 - 0
src/pages/media/Device/Channel/service.ts

@@ -17,6 +17,9 @@ class Service extends BaseService<ChannelItem> {
   saveChannel = (data: any) => request(`${this.uri}/channel`, { method: 'POST', data });
 
   removeChannel = (id: string) => request(`${this.uri}/channel/${id}`, { method: 'DELETE' });
+
+  // 设备详情
+  deviceDetail = (id: string) => request(`${this.uri}/device/${id}`, { method: 'GET' });
 }
 
 export default Service;

+ 13 - 0
src/pages/media/SplitScreen/index.less

@@ -1,3 +1,4 @@
+@import '~antd/es/style/themes/default.less';
 @padding: 20px;
 
 .split-screen {
@@ -7,6 +8,18 @@
     width: 300px;
     padding-right: @padding;
     border-right: 1px solid #f0f0f0;
+
+    .online {
+      color: @success-color;
+    }
+
+    .offline {
+      color: @disabled-color;
+    }
+
+    .left-search {
+      margin-bottom: 12px;
+    }
   }
 
   .right-content {

+ 4 - 0
src/pages/media/SplitScreen/service.ts

@@ -18,3 +18,7 @@ export const ptzStop = (deviceId: string, channelId: string) =>
 // 云台控制-缩放、转向等
 export const ptzTool = (deviceId: string, channelId: string, direct: string, speed: number = 90) =>
   request(`${url}/device/${deviceId}/${channelId}/_pzt/${direct}/${speed}`, { method: 'POST' });
+
+// 查询设备通道列表
+export const queryChannel = (data: any) =>
+  request(`${url}/channel/_query`, { method: 'POST', data });

+ 156 - 10
src/pages/media/SplitScreen/tree.tsx

@@ -1,26 +1,171 @@
 import { Input, Tree } from 'antd';
-import { getMediaTree } from './service';
-import { useRequest } from 'umi';
-import { useEffect } from 'react';
+import { getMediaTree, queryChannel } from './service';
+import React, { useCallback, useEffect, useState, useRef } from 'react';
+import { SearchOutlined, VideoCameraOutlined } from '@ant-design/icons';
+import { debounce } from 'lodash';
 
 type LeftTreeTYpe = {
   onSelect?: (deviceId: string) => void;
 };
 
+interface DataNode {
+  name: string;
+  id: string;
+  isLeaf?: boolean;
+  channelNumber?: number;
+  icon?: React.ReactNode;
+  status: {
+    text: string;
+    value: string;
+  };
+  children?: DataNode[];
+}
+
 const LeftTree = (props: LeftTreeTYpe) => {
-  const { data, run: queryTree } = useRequest(getMediaTree, {
-    manual: true,
-  });
+  const [treeData, setTreeData] = useState<DataNode[]>([]);
+  const treeDataCache = useRef<DataNode[]>([]);
+
+  /**
+   * 是否为子节点
+   * @param node
+   */
+  const isLeaf = (node: DataNode): boolean => {
+    if (node.channelNumber) {
+      return false;
+    }
+    return true;
+  };
+
+  /**
+   * 获取设备列表
+   */
+  const getDeviceList = async () => {
+    const resp = await getMediaTree({ paging: false });
+    if (resp.status === 200) {
+      setTreeData(
+        resp.result.map((item: any) => {
+          const extra: any = {};
+          extra.isLeaf = isLeaf(item);
+
+          return {
+            ...item,
+            ...extra,
+          };
+        }),
+      );
+    }
+  };
+
+  const updateTreeData = (list: DataNode[], key: React.Key, children: DataNode[]): DataNode[] => {
+    return list.map((node) => {
+      if (node.id === key) {
+        return {
+          ...node,
+          children: node.children ? [...node.children, ...children] : children,
+        };
+      }
+
+      if (node.children) {
+        return {
+          ...node,
+          children: updateTreeData(node.children, key, children),
+        };
+      }
+      return node;
+    });
+  };
+
+  /**
+   * 获取子节点
+   * @param key
+   * @param params
+   */
+  const getChildren = (key: React.Key, params: any): Promise<any> => {
+    return new Promise(async (resolve) => {
+      const resp = await queryChannel(params);
+      if (resp.status === 200) {
+        const { total, pageIndex, pageSize } = resp.result;
+        setTreeData((origin) => {
+          const data = updateTreeData(
+            origin,
+            key,
+            resp.result.data.map((item: DataNode) => ({
+              ...item,
+              icon: <VideoCameraOutlined className={item.status.value} />,
+              isLeaf: isLeaf(item),
+            })),
+          );
+
+          if (total > (pageIndex + 1) * pageSize) {
+            setTimeout(() => {
+              getChildren(key, {
+                ...params,
+                pageIndex: params.pageIndex + 1,
+              });
+            }, 50);
+          }
+
+          return data;
+        });
+        resolve(resp.result);
+      }
+    });
+  };
+
+  const onLoadData = ({ key, children }: any): Promise<void> => {
+    return new Promise(async (resolve) => {
+      if (children) {
+        resolve();
+        return;
+      }
+      await getChildren(key, {
+        pageIndex: 0,
+        pageSize: 100,
+        terms: [
+          {
+            column: 'deviceId',
+            value: key,
+          },
+        ],
+      });
+      resolve();
+    });
+  };
+
+  const ThreeNodeSearch = useCallback(
+    (e: any) => {
+      const value = e.target.value;
+      // 缓存treeData数据
+      if (!treeDataCache.current.length) {
+        treeDataCache.current = treeData;
+      }
+
+      if (value) {
+        setTreeData(treeData.filter((node) => node.name.includes(value)));
+      } else {
+        setTreeData(treeDataCache.current);
+        treeDataCache.current = [];
+      }
+    },
+    [treeData],
+  );
 
   useEffect(() => {
-    queryTree({ paging: false });
+    getDeviceList();
   }, []);
 
   return (
     <div className="left-content">
-      <Input.Search />
+      <Input
+        className={'left-search'}
+        placeholder={'请输入设备名称'}
+        suffix={<SearchOutlined />}
+        onChange={debounce(ThreeNodeSearch, 300)}
+      />
       <Tree
-        height={500}
+        showIcon
+        showLine={{ showLeafIcon: false }}
+        height={550}
         fieldNames={{
           title: 'name',
           key: 'id',
@@ -30,7 +175,8 @@ const LeftTree = (props: LeftTreeTYpe) => {
             props.onSelect(key[0] as string);
           }
         }}
-        treeData={data}
+        loadData={onLoadData}
+        treeData={treeData}
       />
     </div>
   );