xjj 2 anni fa
parent
commit
6288f426d9
34 ha cambiato i file con 756 aggiunte e 108 eliminazioni
  1. 5 0
      package.json
  2. 13 3
      src/Frameworks/SysPage.ts
  3. 8 0
      src/Frameworks/SysRouter/index.ts
  4. 15 15
      src/Project/Functions/FuncMain.ts
  5. 0 2
      src/Project/Functions/Handlers/PlatformMenuHandle.ts
  6. 2 5
      src/Project/Functions/LevelAFunctions/FuncDataMeter.ts
  7. 4 7
      src/Project/Functions/LevelAFunctions/FuncLimitedSpace.ts
  8. 3 8
      src/Project/Functions/LevelAFunctions/FuncLogin.ts
  9. 2 3
      src/Project/Functions/LevelAFunctions/FuncMap.ts
  10. 2 4
      src/Project/Functions/LevelAFunctions/FuncPlatformMenu.ts
  11. 28 0
      src/Project/Functions/LevelAFunctions/FuncProjectMenu.tsx
  12. 2 3
      src/Project/Functions/LevelAFunctions/FuncProjectSelection.ts
  13. 2 3
      src/Project/Functions/LevelBFunctions/FuncProjectDetail.ts
  14. 16 1
      src/Project/Os.ts
  15. 6 5
      src/Project/constants/index.ts
  16. 104 0
      src/Project/pages/DataMeter/EditMould.tsx
  17. 2 2
      src/Project/pages/DataMeter/Model/FileManagement.tsx
  18. 1 1
      src/Project/pages/DataMeter/Model/PlanManagement.tsx
  19. 4 5
      src/Project/pages/DataMeter/Model/filemanager-connector/utils/download.js
  20. 4 4
      src/Project/pages/DataMeter/Model/filemanager-connector/utils/see.js
  21. 45 19
      src/Project/pages/DataMeter/index.tsx
  22. 3 3
      src/Project/pages/LimitedSpace/List.js
  23. 2 2
      src/Project/pages/LimitedSpace/index.js
  24. 151 0
      src/Project/pages/ProjectMenu/MenuStyle.less
  25. 225 0
      src/Project/pages/ProjectMenu/index.tsx
  26. 5 2
      src/Project/pages/ProjectSelect/index.js
  27. 2 2
      src/Project/pages/ProjectSelect/index.less
  28. 2 5
      src/Project/pages/home.tsx
  29. 10 0
      src/Project/services/platformMenu.ts
  30. 27 0
      src/Project/services/typings.d.ts
  31. 25 0
      src/Project/utils/index.ts
  32. 2 1
      src/app.ts
  33. 4 0
      src/global.ts
  34. 30 3
      yarn.lock

+ 5 - 0
package.json

@@ -18,12 +18,17 @@
     "@types/react-grid-layout": "^1.3.2",
     "@umijs/max": "^4.0.41",
     "antd": "^5.0.0",
+    "array-move": "^3.0.1",
     "echarts": "^5.4.1",
+    "file-saver": "1.3.3",
     "flv.js": "^1.6.2",
+    "jszip": "^3.5.0",
     "pinyin-match": "^1.2.2",
     "react-grid-layout": "^1.2.5",
     "react-id-swiper": "^2.4.0",
+    "react-sortable-hoc": "^2.0.0",
     "react-zmage": "^0.8.5-beta.37",
+    "superagent": "3.8.3",
     "swiper": "^5.4.5"
   },
   "devDependencies": {

+ 13 - 3
src/Frameworks/SysPage.ts

@@ -2,19 +2,22 @@ import System from '@/Engine/ECS/System';
 import { PAGE_KEY } from '@/Project/constants';
 import { getDvaApp } from 'umi';
 
-class SysRouter extends System {
+class SysPage extends System {
   dispatch: any;
   constructor(name: string) {
     super(name);
-    this.dispatch = getDvaApp()._store.dispatch;
   }
 
+  public onActived(): void {
+    this.dispatch = getDvaApp()._store.dispatch;
+  }
   /**
    * 新增界面
    * @param key 页面的唯一key
    * @param params 页面的参数
    */
   add(key: PAGE_KEY, params?: any) {
+    if(!this.IsActive) return;
     this.dispatch({
       type: 'page/add',
       payload: { key, params },
@@ -22,6 +25,7 @@ class SysRouter extends System {
   }
   // 删除选中页面
   remove() {
+    if(!this.IsActive) return;
     this.dispatch({
       type: 'page/remove',
       payload: {},
@@ -29,6 +33,7 @@ class SysRouter extends System {
   }
   // 根据pageId删除页面
   removeById(id?: number) {
+    if(!this.IsActive) return;
     this.dispatch({
       type: 'page/remove',
       payload: { id },
@@ -36,6 +41,7 @@ class SysRouter extends System {
   }
   // 根据pageId删除页面
   removeByKey(key?: PAGE_KEY) {
+    if(!this.IsActive) return;
     this.dispatch({
       type: 'page/removeByKey',
       payload: { key },
@@ -49,6 +55,7 @@ class SysRouter extends System {
    * @param id 待跳转的pageID
    */
   push(key: string, params?: any, id?: number) {
+    if(!this.IsActive) return;
     this.dispatch({
       type: 'page/replace',
       payload: { key, params, id },
@@ -59,6 +66,7 @@ class SysRouter extends System {
    * @param id 待返回的pageID
    */
   back(id?: number) {
+    if(!this.IsActive) return;
     this.dispatch({
       type: 'page/back',
       payload: { id },
@@ -70,6 +78,7 @@ class SysRouter extends System {
    * @param options 界面的配置信息
    */
   zoomOut(index: number, options: GT.IPageOptions) {
+    if(!this.IsActive) return;
     this.dispatch({
       type: 'page/zoomOut',
       payload: { index, options },
@@ -80,6 +89,7 @@ class SysRouter extends System {
    * @param index 界面的index
    */
   zoomIn(index: number) {
+    if(!this.IsActive) return;
     this.dispatch({
       type: 'page/zoomIn',
       payload: { index },
@@ -87,4 +97,4 @@ class SysRouter extends System {
   }
 }
 
-export default new SysRouter('SysRouter');
+export default SysPage;

+ 8 - 0
src/Frameworks/SysRouter/index.ts

@@ -70,6 +70,14 @@ export const route: GT.IRouterOptions[] = [
       header: false,
     },
   },
+  {
+    key: PAGE_KEY.ProjectMenu,
+    //@ts-ignore
+    component: () => import('@/Project/pages/DataMeter'),
+    options: {
+      header: false,
+    },
+  },
 ];
 
 let Pages: { [key: string]: any } = {};

+ 15 - 15
src/Project/Functions/FuncMain.ts

@@ -16,22 +16,22 @@ export default class FuncMain extends Func<FuncMainState> {
   constructor(name: string) {
     super(name);
     super.initStates((sm) => {
-      // sm.addState(
-      //   FuncMainState.ProjectSelection,
-      //   () => window.GT_APP.funcProjectSelection.setActive(true),
-      //   () => null,
-      //   () => window.GT_APP.funcProjectSelection.setActive(false),
-      // );
+      sm.addState(
+        FuncMainState.ProjectSelection,
+        () => window.GT_APP.funcProjectSelection.setActive(true),
+        () => null,
+        () => window.GT_APP.funcProjectSelection.setActive(false),
+      );
 
-      // sm.addState(FuncMainState.Login, new LoginHandle());
-      // sm.addState(FuncMainState.DataMeter, new DataMeterHandle());
-      // sm.addState(FuncMainState.PlatformMenu, new PlatformMenuHandle());
-      // sm.addState(
-      //   FuncMainState.Map,
-      //   () => window.GT_APP.funcMap.setActive(true),
-      //   () => null,
-      //   () => window.GT_APP.funcMap.setActive(false),
-      // );
+      sm.addState(FuncMainState.Login, new LoginHandle());
+      sm.addState(FuncMainState.DataMeter, new DataMeterHandle());
+      sm.addState(FuncMainState.PlatformMenu, new PlatformMenuHandle());
+      sm.addState(
+        FuncMainState.Map,
+        () => window.GT_APP.funcMap.setActive(true),
+        () => null,
+        () => window.GT_APP.funcMap.setActive(false),
+      );
       sm.addState(FuncMainState.PlatformMenu, () => {
         window.GT_APP.funcPageMenu.setActive(true);
         window.GT_APP.funcPageMenu.changeState(FuncPageMenuState.ProjectDetail);

+ 0 - 2
src/Project/Functions/Handlers/PlatformMenuHandle.ts

@@ -1,6 +1,4 @@
 import StateHandler from '@/Engine/StateMahines/StateHandler';
-import SysPage from '@/Frameworks/SysPage';
-import { PAGE_KEY } from '@/Project/constants';
 import { FuncMainState } from '../FuncMain';
 
 export default class PlatformMenuHandle implements StateHandler<FuncMainState> {

+ 2 - 5
src/Project/Functions/LevelAFunctions/FuncDataMeter.ts

@@ -1,8 +1,5 @@
 import Func from '@/Engine/ECS/Function';
-import SysPage from '@/Frameworks/SysPage';
-import { STORAGE_TYPE, LocalService } from '@/Frameworks/SysStorage';
 import { PAGE_KEY } from '@/Project/constants';
-import { FuncMainState } from '../FuncMain';
 
 export enum FuncDataMeterState {
   idle,
@@ -21,11 +18,11 @@ export default class FuncDataMeter extends Func<FuncDataMeterState> {
     });
   }
   onIdleStateIn(): void {
-    SysPage.add(PAGE_KEY.DataMeter, {
+    window.GT_APP.sysPage.add(PAGE_KEY.DataMeter, {
       subModule: 2,
     });
   }
   onIdleStateExit(): void {
-    SysPage.removeByKey(PAGE_KEY.DataMeter);
+    window.GT_APP.sysPage.removeByKey(PAGE_KEY.DataMeter);
   }
 }

+ 4 - 7
src/Project/Functions/LevelAFunctions/FuncLimitedSpace.ts

@@ -1,8 +1,5 @@
 import Func from '@/Engine/ECS/Function';
-import SysPage from '@/Frameworks/SysPage';
-import { STORAGE_TYPE, LocalService } from '@/Frameworks/SysStorage';
 import { PAGE_KEY } from '@/Project/constants';
-import { FuncMainState } from '../FuncMain';
 
 export enum FuncLimitedSpaceState {
   idle,
@@ -41,15 +38,15 @@ export default class FuncLimitedSpace extends Func<FuncLimitedSpaceState> {
   onIdleStateExit(): void {
   }
   onIndexStateIn(): void {
-    SysPage.add(PAGE_KEY.LimitedIndex)
+    window.GT_APP.sysPage.add(PAGE_KEY.LimitedIndex)
   }
   onIndexStateExit(): void {
-    SysPage.removeByKey(PAGE_KEY.LimitedIndex)
+    window.GT_APP.sysPage.removeByKey(PAGE_KEY.LimitedIndex)
   }
   onDataStateIn(): void {
-    SysPage.add(PAGE_KEY.LimitedData)
+    window.GT_APP.sysPage.add(PAGE_KEY.LimitedData)
   }
   onDataStateExit(): void {
-    SysPage.removeByKey(PAGE_KEY.LimitedData)
+    window.GT_APP.sysPage.removeByKey(PAGE_KEY.LimitedData)
   }
 }

+ 3 - 8
src/Project/Functions/LevelAFunctions/FuncLogin.ts

@@ -1,5 +1,4 @@
 import Func from '@/Engine/ECS/Function';
-import SysPage from '@/Frameworks/SysPage';
 import { STORAGE_TYPE, LocalService } from '@/Frameworks/SysStorage';
 import { PAGE_KEY } from '@/Project/constants';
 import { FuncMainState } from '../FuncMain';
@@ -23,17 +22,13 @@ export default class FuncLogin extends Func<FuncLoginState> {
   onIdleStateIn(): void {
     const login = (token: string) => {
       LocalService.setItem(STORAGE_TYPE.token, token);
-      window.GT_APP.funcMain.changeState(FuncMainState.PlatformMenu);
+      window.GT_APP.funcMain.changeState(FuncMainState.ProjectSelection);
     };
-    SysPage.add(PAGE_KEY.Login, {
+    window.GT_APP.sysPage.add(PAGE_KEY.Login, {
       login,
     });
   }
   onIdleStateExit(): void {
-    SysPage.removeByKey(PAGE_KEY.Login);
-  }
-  login(token: string) {
-    LocalService.setItem(STORAGE_TYPE.token, token);
-    window.GT_APP.funcMain.changeState(FuncMainState.PlatformMenu);
+    window.GT_APP.sysPage.removeByKey(PAGE_KEY.Login);
   }
 }

+ 2 - 3
src/Project/Functions/LevelAFunctions/FuncMap.ts

@@ -1,5 +1,4 @@
 import Func from '@/Engine/ECS/Function';
-import SysPage from '@/Frameworks/SysPage';
 import { PAGE_KEY } from '@/Project/constants';
 export enum FuncMapState {
   Map,
@@ -13,9 +12,9 @@ export default class FuncMap extends Func<FuncMapState> {
     });
   }
   onStateIn(): void {
-    SysPage.add(PAGE_KEY.Map);
+    window.GT_APP.sysPage.add(PAGE_KEY.Map);
   }
   onStateExit(): void {
-    SysPage.removeByKey(PAGE_KEY.Map);
+    window.GT_APP.sysPage.removeByKey(PAGE_KEY.Map);
   }
 }

+ 2 - 4
src/Project/Functions/LevelAFunctions/FuncPlatformMenu.ts

@@ -1,8 +1,6 @@
 import Func from '@/Engine/ECS/Function';
-import SysPage from '@/Frameworks/SysPage';
 import { PAGE_KEY } from '@/Project/constants';
 import { FuncMainState } from '../FuncMain';
-import FuncMap from './FuncMap';
 export enum FuncPlatformMenuState {
   PlatformMenu,
 }
@@ -23,9 +21,9 @@ export default class FuncPlatformMenu extends Func<FuncPlatformMenuState> {
     const handleMapPage = (state: FuncMainState): void => {
       window.GT_APP.funcMain.changeState(state);
     };
-    SysPage.add(PAGE_KEY.PlatformMenu, { handleMapPage });
+    window.GT_APP.sysPage.add(PAGE_KEY.PlatformMenu, { handleMapPage });
   }
   onStateExit(): void {
-    SysPage.removeByKey(PAGE_KEY.PlatformMenu);
+    window.GT_APP.sysPage.removeByKey(PAGE_KEY.PlatformMenu);
   }
 }

+ 28 - 0
src/Project/Functions/LevelAFunctions/FuncProjectMenu.tsx

@@ -0,0 +1,28 @@
+import Func from '@/Engine/ECS/Function';
+import { PAGE_KEY } from '@/Project/constants';
+export enum FuncProjectMenuState {
+  ProjectMenu,
+}
+
+export default class FuncProjectMenu extends Func<FuncProjectMenuState> {
+  constructor(name: string) {
+    super(name);
+    super.initStates((sm) => {
+      sm.addState(
+        FuncProjectMenuState.ProjectMenu,
+        this.onStateIn,
+        null,
+        this.onStateExit,
+      );
+    });
+  }
+  onStateIn(): void {
+    const clickMenu = (menu: any): void => {
+      console.log(menu);
+    };
+    window.GT_APP.sysPage.add(PAGE_KEY.ProjectMenu, { clickMenu });
+  }
+  onStateExit(): void {
+    window.GT_APP.sysPage.removeByKey(PAGE_KEY.ProjectMenu);
+  }
+}

+ 2 - 3
src/Project/Functions/LevelAFunctions/FuncProjectSelection.ts

@@ -1,5 +1,4 @@
 import Func from '@/Engine/ECS/Function';
-import SysPage from '@/Frameworks/SysPage';
 import { PAGE_KEY } from '@/Project/constants';
 export enum FuncProjectSelectionState {
   idle,
@@ -21,12 +20,12 @@ export default class FuncProjectSelection extends Func<FuncProjectSelectionState
     const selectProject = (projcet: Api.IProject) => {
       console.log(projcet);
     };
-    SysPage.add(PAGE_KEY.ProjectSelection, {
+    window.GT_APP.sysPage.add(PAGE_KEY.ProjectSelection, {
       selectProject,
       subModule: 1,
     });
   }
   onIdleStateExit(): void {
-    SysPage.removeByKey(PAGE_KEY.ProjectSelection);
+    window.GT_APP.sysPage.removeByKey(PAGE_KEY.ProjectSelection);
   }
 }

+ 2 - 3
src/Project/Functions/LevelBFunctions/FuncProjectDetail.ts

@@ -1,5 +1,4 @@
 import Func from '@/Engine/ECS/Function';
-import SysPage from '@/Frameworks/SysPage';
 import { PAGE_KEY } from '@/Project/constants';
 
 export enum FuncProjectDetailState {
@@ -13,9 +12,9 @@ export default class FuncProjectDetail extends Func<FuncProjectDetailState> {
     });
   }
   onIdleStateIn(): void {
-    SysPage.add(PAGE_KEY.ProjectDetail);
+    window.GT_APP.sysPage.add(PAGE_KEY.ProjectDetail);
   }
   onIdleStateExit(): void {
-    SysPage.removeByKey(PAGE_KEY.ProjectDetail);
+    window.GT_APP.sysPage.removeByKey(PAGE_KEY.ProjectDetail);
   }
 }

+ 16 - 1
src/Project/Os.ts

@@ -5,7 +5,9 @@ import FuncMap from './Functions/LevelAFunctions/FuncMap';
 import FuncPlatformMenu from './Functions/LevelAFunctions/FuncPlatformMenu';
 import FuncProjectSelection from './Functions/LevelAFunctions/FuncProjectSelection';
 import FuncPageMenu from './Functions/LevelAFunctions/FuncPageMenu';
+import SysPage from '@/Frameworks/SysPage';
 class Os {
+  isActive: Boolean = false;
   funcMain: FuncMain;
   funcLogin: FuncLogin;
   funcPlatformMenu: FuncPlatformMenu;
@@ -16,7 +18,10 @@ class Os {
 
   funcPageMenu: FuncPageMenu;
 
+  sysPage: SysPage;
+
   constructor() {
+    // func
     this.funcMain = new FuncMain('FuncMain');
     this.funcLogin = new FuncLogin('FuncLogin');
     this.funcPlatformMenu = new FuncPlatformMenu('FuncPlatformMenu');
@@ -26,7 +31,17 @@ class Os {
     );
 
     this.funcDataMeter = new FuncDataMeter('FuncDataMeter');
-    this.funcPageMenu = new FuncPageMenu("FuncPageMenu");
+    this.funcPageMenu = new FuncPageMenu('FuncPageMenu');
+
+    // sys
+    this.sysPage = new SysPage('SysRouter');
+  }
+
+  init() {
+    this.sysPage.setActive(true);
+
+    this.funcMain.setActive(true);
+    this.isActive = true;
   }
 }
 

+ 6 - 5
src/Project/constants/index.ts

@@ -1,11 +1,12 @@
 export enum PAGE_KEY {
   Home,
   Access,
-  Login,
-  PlatformMenu,
-  ProjectSelection,
-  Map,
-  DataMeter,
+  Login, // 登录页
+  PlatformMenu, // 首页
+  ProjectSelection, // 项目
+  ProjectMenu, // 项目菜单页
+  Map, // 全局驾驶舱
+  DataMeter, // 项目驾驶舱
   ProjectDetail,//项目详情
 }
 

+ 104 - 0
src/Project/pages/DataMeter/EditMould.tsx

@@ -0,0 +1,104 @@
+import React, { useEffect, useState } from 'react';
+import { Checkbox, Row, Col, Button, Modal } from 'antd';
+// import arrayMove from 'array-move';
+// import { SortableContainer, SortableElement } from 'react-sortable-hoc';
+// import WriteButton from '../Button/writeButton';
+
+// const SortableItem = SortableElement(({ value }: any) => (
+//   <li
+//     style={{
+//       zIndex: 9999,
+//       visibility: 'visible',
+//       fontSize: '18px',
+//       color: '#D7E4E8',
+//       marginBottom: '10px',
+//     }}
+//   >
+//     {value}
+//   </li>
+// ));
+// const SortableContainerDom = SortableContainer(({ children }: any) => {
+//   return <ul>{children}</ul>;
+// });
+function EditMould(props: any) {
+  const {
+    title,
+    visible,
+    onOk,
+    onCancel,
+    setModelCheck,
+    modelCheck,
+    currentModel,
+    // setCurrentModel,
+  } = props;
+  // const [items, setItems] = useState([]);
+  // const [sortVisible, setSortVisible] = useState(false);
+  // const onSortEnd = ({ oldIndex, newIndex }: any) => {
+  //   setItems(arrayMove(items, oldIndex, newIndex));
+  // };
+
+  // const handleOk = () => {
+  //   var tempCurrentModel = currentModel;
+  //   tempCurrentModel.child = items;
+  //   setCurrentModel?.(tempCurrentModel);
+  //   setSortVisible(false);
+  // };
+  // const HandleSortBtnClick = () => {
+  //   setSortVisible(true);
+  //   setItems(currentModel.child);
+  // };
+
+  return (
+    <Modal
+      title={title}
+      open={visible}
+      onOk={onOk}
+      onCancel={onCancel}
+      footer={[
+        // <Button key="submit" type="primary" onClick={HandleSortBtnClick}>
+        //   排序
+        // </Button>,
+        <Button key="back" onClick={onCancel}>
+          取消
+        </Button>,
+        <Button key="submit" type="primary" onClick={onOk}>
+          确定
+        </Button>,
+      ]}
+    >
+      <Checkbox.Group
+        style={{ width: '100%' }}
+        onChange={setModelCheck}
+        value={modelCheck}
+      >
+        <Row>
+          {currentModel &&
+            (currentModel.child || []).map((item: any) => (
+              <Col key={item.key} span={8}>
+                <Checkbox value={item.key}>{item.title}</Checkbox>
+              </Col>
+            ))}
+        </Row>
+      </Checkbox.Group>
+      {/* <Modal
+        title="排序子模块"
+        visible={sortVisible}
+        onOk={handleOk}
+        onCancel={() => {
+          setSortVisible(false);
+        }}
+      >
+        <SortableContainerDom helpClass="sortEditMould" onSortEnd={onSortEnd}>
+        {(items || []).map((value, index) => (
+            <SortableItem
+              key={`item-${value}`}
+              index={index}
+              value={value.title}
+            />
+          ))}
+        </SortableContainerDom>
+      </Modal> */}
+    </Modal>
+  );
+}
+export default EditMould;

+ 2 - 2
src/Project/pages/DataMeter/Model/FileManagement.tsx

@@ -1,7 +1,7 @@
 import React, { useState } from 'react';
 import { Button } from 'antd';
-// import { GetTokenFromUrl } from '@/utils/utils';
-import style from './index.less';
+// import { getToken } from '@/utils/utils';
+import style from '../index.less';
 // import ModelTitle from '@/components/ModelTitle';
 import { ChartBoxTitle } from './ChartBox';
 import { Empty } from 'antd';

+ 1 - 1
src/Project/pages/DataMeter/Model/PlanManagement.tsx

@@ -1,7 +1,7 @@
 import React, { useState, useEffect, useRef } from 'react';
 import { Empty } from 'antd';
 import * as echarts from 'echarts';
-import style from './index.less';
+import style from '../index.less';
 import moment from 'moment';
 import { ChartBoxTitle } from './ChartBox';
 import { useRequest } from '@umijs/max';

+ 4 - 5
src/Project/pages/DataMeter/Model/filemanager-connector/utils/download.js

@@ -1,11 +1,10 @@
 import FileSaver from 'file-saver';
-import {GetTokenFromUrl} from "@/utils/utils";
-import {GetFileDownloadUrl} from '@/services/api'
-import {downloadFile} from '../../utils';
+import { getToken, downloadFile } from '@/Project/utils';
+import { request } from '@umijs/max';
 
 // a case when we need to silently download a file using Javascript, and prompt to save it afterwards
 function promptToSaveBlob({ content, name, downloadUrl }) {
-  const DownloadUrl = `${downloadUrl}&JWT-TOKEN=${GetTokenFromUrl()}`;
+  const DownloadUrl = `${downloadUrl}&JWT-TOKEN=${getToken()}`;
   if (downloadUrl) {
     // const iframeId = 'oc-fm--filemanager-download-iframe';
     // let iframeDOMNode = document.getElementById(iframeId);
@@ -18,7 +17,7 @@ function promptToSaveBlob({ content, name, downloadUrl }) {
     // }
     //
     // iframeDOMNode.src = downloadUrl;
-    GetFileDownloadUrl(DownloadUrl).then(ret => {
+    request(DownloadUrl).then(ret => {
       if (ret !== false && ret.status !== 600) {
         downloadFile(ret, name)
       }

+ 4 - 4
src/Project/pages/DataMeter/Model/filemanager-connector/utils/see.js

@@ -1,10 +1,10 @@
 import FileSaver from 'file-saver';
-import { GetTokenFromUrl } from '@/utils/utils';
-import { GetFileDownloadUrl } from '@/services/api';
+import { getToken } from '@/Project/utils';
+import { request } from '@umijs/max';
 // a case when we need to silently download a file using Javascript, and prompt to save it afterwards
 function promptToSaveBlob({ content, name, downloadUrl }) {
-  downloadUrl = `${downloadUrl}&JWT-TOKEN=${GetTokenFromUrl()}`;
-  GetFileDownloadUrl(downloadUrl).then(ret => {
+  downloadUrl = `${downloadUrl}&JWT-TOKEN=${getToken()}`;
+  request(downloadUrl).then(ret => {
     console.log(ret);
     if (window.InvokeUnityFileOpener) {
       window.InvokeUnityFileOpener(ret);

+ 45 - 19
src/Project/pages/DataMeter/index.tsx

@@ -22,14 +22,17 @@ import {
 import CreateMould from './CreateMould';
 import DrawerLeft from './DrawerLeft';
 import MouldDrawerLeft from './MouldDrawerLeft';
+import EditMould from './EditMould';
 
 const gridWidth = document.documentElement.clientWidth;
 
 function DataMeter(props: DataMeter.IProps) {
   // const data = useMo
-  const {
-    initialState: { projectId },
-  } = useModel('@@initialState');
+  // const {
+  //   initialState: { projectId },
+  // } = useModel('@@initialState');
+  const { project } = useModel('project');
+  const projectId = project?.ID || 0
 
   const { hasModel, isNew, params } = props;
   const { subModule } = params;
@@ -180,6 +183,33 @@ function DataMeter(props: DataMeter.IProps) {
     console.log('add model=========', layout);
     setLayout(JSON.parse(JSON.stringify(layout)));
   };
+  // 子模块完成编辑的回调函数
+  const handleOk = () => {
+    let count = 0;
+    let firstShowActive: string | number;
+    let currentChild: DataMeter.ILayoutChild;
+    if (!currentModel || !currentModel.child) return;
+    currentModel.child.forEach((item) => {
+      item.show = modelCheck.indexOf(item.key) != -1;
+      if (item.show) {
+        count++;
+        if (!firstShowActive) firstShowActive = item.key;
+      }
+      if (item.key == currentModel.active) {
+        currentChild = item;
+      }
+    });
+    if (count == 0) {
+      message.error('至少显示一个内容!');
+      return;
+    }
+    // 如果选中项被取消,将第一个显示的项设置为选中项
+    if (currentChild! && !currentChild.show)
+      currentModel.active = firstShowActive!;
+    // 保存选中的子模块
+    setLayout(JSON.parse(JSON.stringify(layout)));
+    setEditVisible(false);
+  };
   // 保存配置
   const saveLayout = async (newLayout: DataMeter.ILayout[], isDefault = 0) => {
     let id,
@@ -256,7 +286,6 @@ function DataMeter(props: DataMeter.IProps) {
   return (
     <div
       className={`dataMeter ${style.dataMeter} ${!edit ? style.noScroll : ''}`}
-      // onDragEnd={onDragEnd}
       style={{ minHeight: '100vh' }}
     >
       <CreateMould
@@ -285,21 +314,18 @@ function DataMeter(props: DataMeter.IProps) {
         visible={mouldVisible}
         mouldSave={saveMould}
       ></MouldDrawerLeft>
-      {/*
-       */}
-      {/*         
-        <EditMould
-          title="编辑子模块"
-          visible={editVisible}
-          onOk={handleOk}
-          onCancel={() => {
-            setEditVisible(false);
-          }}
-          setModelCheck={setModelCheck}
-          modelCheck={modelCheck}
-          setCurrentModel={setCurrentModel}
-          currentModel={currentModel}
-        ></EditMould> */}
+      <EditMould
+        title="编辑子模块"
+        visible={editVisible}
+        onOk={handleOk}
+        onCancel={() => {
+          setEditVisible(false);
+        }}
+        setModelCheck={setModelCheck}
+        modelCheck={modelCheck}
+        setCurrentModel={setCurrentModel}
+        currentModel={currentModel}
+      ></EditMould>
       <div className={style.gridBox}>
         <GridLayout
           className="layout"

+ 3 - 3
src/Project/pages/LimitedSpace/List.js

@@ -16,7 +16,7 @@ import {
   message,
 } from 'antd';
 import router from 'umi/router';
-import { UnityAction, getToken, GetTokenFromUrl } from '@/utils/utils';
+import { UnityAction, getToken, getToken } from '@/utils/utils';
 import styles from './LimitedSpace.less';
 import project from '@/models/project';
 import SearchModal from './SearchModal';
@@ -37,7 +37,7 @@ function List(props) {
 
   const clickDetail = record => {
     setCurrentItem(record);
-    let url = `/unity/limitedSpace/detail/${projectId}/${record.id}?JWT-TOKEN=${GetTokenFromUrl()}`;
+    let url = `/unity/limitedSpace/detail/${projectId}/${record.id}?JWT-TOKEN=${getToken()}`;
 
     if (!group_id) UnityAction.sendMsg('SpaceDatasFromWeb', JSON.stringify([record]));
     else url = url.concat(`&group_id=${group_id}`);
@@ -199,7 +199,7 @@ function List(props) {
             setCurrentItem(record);
             let url = `/unity/limitedSpace/detail/${projectId}/${
               record.id
-            }?JWT-TOKEN=${GetTokenFromUrl()}`;
+            }?JWT-TOKEN=${getToken()}`;
             if (group_id) url = url.concat(`&group_id=${group_id}`);
             router.push(url);
           });

+ 2 - 2
src/Project/pages/LimitedSpace/index.js

@@ -4,7 +4,7 @@
 // import { connect } from 'dva';
 // import { Row, Col, Button } from 'antd';
 // import router from 'umi/router';
-// import { UnityAction, GetTokenFromUrl } from '@/utils/utils';
+// import { UnityAction, getToken } from '@/utils/utils';
 // import styles from './LimitedSpace.less';
 // import limitedSpace from './models/limitedSpace';
 
@@ -49,7 +49,7 @@
 //     setCurrentArea(item);
 //     UnityAction.sendMsg('AreaSelectFromWeb', JSON.stringify(item));
 //     router.push(
-//       `/unity/limitedSpace/list/${projectId}?JWT-TOKEN=${GetTokenFromUrl()}&group_id=${
+//       `/unity/limitedSpace/list/${projectId}?JWT-TOKEN=${getToken()}&group_id=${
 //         item.group_id
 //       }`
 //     );

+ 151 - 0
src/Project/pages/ProjectMenu/MenuStyle.less

@@ -0,0 +1,151 @@
+.background {
+  background-image: url(@/assets/UnityMenu/background.jpg);
+  width: '100%';
+  height: 100vh;
+  background-size: cover;
+  background-repeat: no-repeat;
+  :global {
+    .ant-popover-inner {
+      background: #0d1a2b;
+    }
+  }
+}
+.menu {
+  width: 1.2rem;
+  height: 1.2rem;
+  background: linear-gradient(0deg, #285098, #1d3969);
+  box-shadow: 0px 3px 0.16rem 2px rgba(0, 0, 0, 0.3), 0px 5px 0.39rem 0.1rem rgba(0, 0, 0, 0.1);
+  border-radius: 50%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  cursor: pointer;
+}
+.TogMenu {
+  background-image: url(@/assets/UnityMenu/TogMenuBackground.png);
+  width: 3.56rem;
+  background-size: cover;
+  background-repeat: no-repeat;
+  position: absolute;
+  top: 0.6rem;
+  left: 0;
+  display: flex;
+  flex-direction: column;
+  z-index: 99999;
+}
+.TogMenuClose {
+  background-image: url(@/assets/UnityMenu/TogMenuClose.png);
+  width: 0.23rem;
+  height: 5px;
+  background-size: cover;
+  background-repeat: no-repeat;
+  position: absolute;
+  right: 0.1rem;
+  top: 0.14rem;
+}
+.TogMenuItem {
+  margin-left: 0.22rem;
+  margin-right: 0.4rem;
+  height: 0.6rem;
+  display: flex;
+  align-items: center;
+  border-bottom: 1px solid rgb(176, 192, 224);
+}
+.TogMenuItemLeftLine {
+  background-image: url(@/assets/UnityMenu/leftLine.png);
+  height: 0.16rem;
+  width: 4px;
+  background-size: cover;
+  background-repeat: no-repeat;
+}
+.TogMenuItemText {
+  font-size: 0.18rem;
+  font-family: 'Microsoft YaHei UI'; /* Microsoft YaHei UI;*/
+  font-weight: 400;
+  color: #ffffff;
+  line-height: 0.34rem;
+  margin-left: 0.18rem;
+  cursor: pointer;
+}
+.menuContent {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: '100%';
+  height: calc(100vh - 0.6rem);
+}
+.menuFriName {
+  font-size: 0.26rem;
+  font-family: 'Microsoft YaHei UI'; /* Microsoft YaHei UI;*/
+  font-weight: 400;
+  color: #ffffff;
+  line-height: 0.45rem;
+  text-shadow: 0px 5px 14px rgba(0, 0, 0, 0.35), 0px 3px 12px rgba(0, 0, 0, 0.19);
+  cursor: pointer;
+  user-select: none;
+  letter-spacing: 2px;
+}
+.card {
+  width: 12rem;
+  height: 6.4rem;
+}
+.wrap {
+  display: flex;
+  flex-wrap: wrap;
+}
+.item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  width: 4rem;
+  height: 2.4rem;
+}
+
+.headerText {
+  width: 6rem;
+  font-size: 0.36rem;
+  font-family: YouSheBiaoTiHei;
+  font-weight: 400;
+  color: #ffffff;
+  line-height: 0.63rem;
+  text-align: center;
+  cursor: default;
+}
+
+.BreadcrumbWrap {
+  position: absolute;
+  left: 0.77rem;
+  top: 0.15rem;
+  height: 0.34rem;
+  // width: 3.4rem;
+  display: flex;
+  align-items: center;
+}
+.BreadcrumbItem {
+  background-size: contain;
+  background-repeat: no-repeat;
+  height: 0.34rem;
+  font-size: 16px;
+  font-family: 'Microsoft YaHei UI'; /* Microsoft YaHei UI;*/
+  font-weight: bold;
+  color: #ffffff;
+  line-height: 0.34rem;
+  background: url(@/assets/UnityMenu/BreadcrumbSelect.png) no-repeat center;
+  background-size: 100% 100%;
+  padding-left: 0.18rem;
+  padding-right: 0.16rem;
+  cursor: pointer;
+  &.active {
+    background-image: url(@/assets/UnityMenu/Breadcrumb.png);
+  }
+}
+
+.BreadcrumbContent {
+  background-image: url(@/assets/UnityMenu/TogMenuBackground.png);
+  width: 2.68rem;
+  background-size: cover;
+  background-repeat: no-repeat;
+  position: absolute;
+  display: flex;
+  flex-direction: column;
+}

+ 225 - 0
src/Project/pages/ProjectMenu/index.tsx

@@ -0,0 +1,225 @@
+import { useRequest } from '@umijs/max';
+import React, { useState, useEffect } from 'react';
+import menuStyle from './MenuStyle.less';
+
+const noIcon = require('@/assets/UnityMenu/noIcon.png');
+const grayIcon = [
+  {
+    code: 'func-01-ops-BaseInfo',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-ops-BaseInfo.png'),
+    name: '水厂介绍',
+  },
+  {
+    code: 'func-01-ops-DataView',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-ops-DataView.png'),
+    name: '数据驾驶舱',
+  },
+  {
+    code: 'func-01-ops-DeviceManagement',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-ops-DeviceManagement.png'),
+    name: '设备管理',
+  },
+  {
+    code: 'func-01-ops-ProManagement',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-ops-ProManagement.png'),
+    name: '生产管理',
+  },
+  {
+    code: 'func-01-ops-SecurityManagement',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-ops-SecurityManagement.png'),
+    name: '安全管理',
+  },
+  {
+    code: 'func-01-ops-LimitedSpace',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-ops-LimitedSpace.png'),
+    name: '有限空间管理',
+  },
+  {
+    code: 'func-01-ops-EnergyManagement',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-ops-EnergyManagement.png'),
+    name: '能耗管理',
+  },
+  {
+    code: 'func-01-ops-WaterQManagement',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-ops-WaterQManagement.png'),
+    name: '水质管理',
+  },
+  {
+    code: 'func-01-build-0',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-build-0.png'),
+    name: '数据中心',
+  },
+  {
+    code: 'func-01-ops-ConfigManagement',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-ops-ConfigManagement.png'),
+    name: '配置管理',
+  },
+
+  {
+    code: 'func-01-build-0',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-build-0.png'),
+    name: '数据中心',
+  },
+  {
+    code: 'func-01-build-3',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-build-3.png'),
+    name: '计划管理',
+  },
+  {
+    code: 'func-01-build-4',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-build-4.png'),
+    name: '安全管理',
+  },
+  {
+    code: 'func-01-build-10',
+    iconPath: require('@/assets/UnityMenu/ICON/func-01-build-10.png'),
+    name: '流程管理',
+  },
+
+  {
+    code: '',
+    iconPath: require('@/assets/UnityMenu/ICON/newModel.png'),
+    name: '新增功能',
+  },
+];
+function ModuleMenu(props: any) {
+  const {
+    location: {
+      query: { moduleCode, projectId },
+    },
+  } = props;
+
+  const { data: waterMenuData } = useRequest(async () => {});
+  const [curMenu, setCurMenu] = useState<Api.IMenu[]>([]);
+
+  // useEffect(() => {
+  //   dispatch({
+  //     type: 'menu/getMenuByDepId',
+  //     callback: menu => {
+  //       let moduleMenu = (menu.children || []).find(item => item.Code == moduleCode);
+  //       if (moduleMenu) initMenu(moduleMenu, handleMenuClick);
+  //     },
+  //     payload: { version: 2, projectId },
+  //   });
+  // }, []);
+
+  const initMenu = (parent: Api.IMenu) => {
+    if (parent?.children) {
+      let menu = [
+        ...parent.children,
+        // {
+        //   Name: '新增功能',
+        //   ID: -1,
+        //   Code: '',
+        //   Type: 1,
+        //   Icon: require('@/assets/UnityMenu/ICON/newModel.png'),
+        //   WebPath: '',
+        //   UnityPath: '',
+        // },
+      ];
+
+      for (let i = 0; i < menu.length; i++) {
+        let element = menu[i];
+        if (element.Type != 1) {
+          menu.splice(i, 1);
+          i--; //i
+          continue;
+        }
+        // element.name = element.Name;
+        // element.iconPath = element.Icon || noIcon;
+        // element.active = element.children != undefined || element.UnityPath != '';
+        if (!element.active) continue;
+      }
+      setCurMenu(menu);
+    }
+  };
+  // const backToProjectSelect = () => {
+  //   UnityAction.sendMsg('back', '');
+  // };
+  const handleMenuClick = (element: Api.IMenu) => {
+    if (!element.active) return;
+    let menu = [];
+    // console.log(element);
+    // UnityAction.sendMsg('EnterApp', element);
+    var parent = waterMenuData?.children.find(
+      (item: Api.IMenu) => item.ID == element.ParentID,
+    );
+    if (parent) {
+      menu.push(parent);
+      var current = parent?.children.find(
+        (item: Api.IMenu) => item.Code == element.Code,
+      );
+      if (current) {
+        menu.push(current);
+      }
+    }
+  };
+
+  return (
+    <>
+      <div className={menuStyle.background}>
+        <div className={menuStyle.menuContent}>
+          <div className={menuStyle.wrap}>
+            {curMenu.map((item) => (
+              <div className={menuStyle.item}>
+                <div
+                  onClick={() => handleMenuClick(item)}
+                  className={menuStyle.menu}
+                  style={
+                    item.active
+                      ? {}
+                      : item.ID === -1
+                      ? { cursor: 'not-allowed' }
+                      : {}
+                  }
+                >
+                  <img
+                    className={menuStyle.pic}
+                    src={
+                      item.active
+                        ? item.Icon ||
+                          require('@/assets/UnityMenu/ICON/newModel.png')
+                        : grayIcon.find((icon) => icon.code === item.Code)
+                            ?.iconPath
+                    }
+                    style={item.active ? {} : { cursor: 'not-allowed' }}
+                  />
+                </div>
+                <div style={{ marginTop: '0.22rem', textAlign: 'center' }}>
+                  <span
+                    className={menuStyle.menuFriName}
+                    style={
+                      item.active
+                        ? {}
+                        : { color: '#6081B2', cursor: 'not-allowed' }
+                    }
+                  >
+                    {item.Name}
+                  </span>
+                </div>
+              </div>
+            ))}
+          </div>
+        </div>
+      </div>
+      {/* {
+        unityBack == undefined && <button
+          className={style.enterBtn}
+          type="button"
+          onClick={e => {
+            backToProjectSelect();
+            e.stopPropagation();
+          }}
+          style={{
+            position: 'absolute',
+            right: 0,
+            top: 100,
+          }}
+        >
+          返回
+        </button>
+      } */}
+    </>
+  );
+}
+export default ModuleMenu;

+ 5 - 2
src/Project/pages/ProjectSelect/index.js

@@ -24,7 +24,9 @@ function ProjectSelect(props) {
   // const inputRef = useRef();
 
   const handleClickProject = (item) => {
+    // console.log(item)
     setProject(item);
+    selectProject()
   };
   const onChangeInput = (e) => {
     setValue(e.target.value);
@@ -116,8 +118,9 @@ function ProjectSelect(props) {
         <div className={style.switch}>
           <Switch
             onChange={onChange}
-            style={{ marginLeft: '0.1rem' }}
-            defaultChecked={forbiddenModel == 0 ? true : false}
+            style={{ marginLeft: '10px' }}
+            defaultChecked={true}
+            // defaultChecked={forbiddenModel == 0 ? true : false}
           />
           加载模型
         </div>

+ 2 - 2
src/Project/pages/ProjectSelect/index.less

@@ -202,7 +202,7 @@
       bottom: 6px;
       left: 50%;
       transform: translateX(-50%);
-      font-size: 26px;
+      font-size: 20px;
       font-family: 'Microsoft YaHei UI';
       font-weight: 400;
       color: #e2f2f7;
@@ -216,7 +216,7 @@
       text-align: center;
       z-index: 2;
       letter-spacing: 2px;
-      font-size: 30px;
+      font-size: 24px;
       font-weight: 300;
       padding-left: 20px;
       padding-right: 20px;

+ 2 - 5
src/Project/pages/home.tsx

@@ -1,12 +1,9 @@
 import { connect } from 'umi';
-import React from 'react';
+import React, { useEffect } from 'react';
 import './global.less';
 import Router from '@/Frameworks/SysRouter';
-import Os from '../Os';
 
-window.GT_APP = new Os();
-window.GT_APP.funcMain.setActive(true);
-// window.GT_APP.funcLimitedSpace.setActive(true);
+window.GT_APP.init()
 
 const Home: React.FC = (props: any) => {
   const {

+ 10 - 0
src/Project/services/platformMenu.ts

@@ -0,0 +1,10 @@
+import { request } from '@umijs/max';
+
+export async function getMenuData(params:any) {
+  return request(`/api/v1/menu`, {
+    params: params,
+  });
+}
+export async function getMenuDataByProject(projectId:string) {
+  return request(`/api/v2/user/project/menu/${projectId}`);
+}

+ 27 - 0
src/Project/services/typings.d.ts

@@ -112,4 +112,31 @@ declare namespace Api {
     Users: IUser[];
     children: IDep[];
   }
+  interface IMenu {
+    AppPath: string;
+    Code: string;
+    CreatedBy: number;
+    CreatedOn: string | null;
+    DeletedBy: number;
+    DeletedFlag: number;
+    DeletedOn: string | null;
+    ID: number;
+    Icon: string;
+    Index: number;
+    Level: number;
+    MenuType: number;
+    Name: string;
+    ParentID: number;
+    ProjectIds: number[] | null;
+    Remark: string;
+    Type: number;
+    UnityPath: string;
+    UpdatedBy: number;
+    UpdatedOn: string | null;
+    Version: number;
+    WebPath: string;
+    children?: IMenu[];
+
+    active?: boolean;
+  }
 }

+ 25 - 0
src/Project/utils/index.ts

@@ -3,3 +3,28 @@ import { LocalService, STORAGE_TYPE } from '@/Frameworks/SysStorage';
 export function getToken(): string {
   return LocalService.getItem(STORAGE_TYPE.token);
 }
+
+export const downloadFile = (
+  url: string,
+  fileName: string,
+  encode?: boolean,
+) => {
+  // if (window.InvokeUnityFileOpener) {
+  //   window.InvokeUnityFileOpener(url);
+  // } else {
+  const downloadLink = document.createElement('a');
+  const body = document.documentElement || document.body;
+  body.appendChild(downloadLink);
+  var tempUrl = url;
+  if (encode) {
+    var urlArr = tempUrl.split('/');
+    urlArr[urlArr.length - 1] = encodeURIComponent(urlArr[urlArr.length - 1]);
+    tempUrl = urlArr.join('/');
+  }
+  downloadLink.href = tempUrl;
+  downloadLink.download = fileName;
+
+  downloadLink.click();
+  body.removeChild(downloadLink);
+  // }
+};

+ 2 - 1
src/app.ts

@@ -8,8 +8,9 @@ import { message } from 'antd';
 export async function getInitialState(): Promise<any> {
   let currentUser = {},
     access = {};
+  let app = window.GT_APP;
   // 非登录页获取用户信息
-  if (!window.GT_APP?.funcLogin?.IsActive) {
+  if (app?.isActive && !app.funcLogin.IsActive) {
     try {
       currentUser = (await queryCurrent()).data;
     } catch (error) {}

+ 4 - 0
src/global.ts

@@ -0,0 +1,4 @@
+import Os from "./Project/Os";
+
+// 初始化Func
+window.GT_APP = new Os();

+ 30 - 3
yarn.lock

@@ -2852,6 +2852,11 @@ array-includes@^3.1.4, array-includes@^3.1.5:
     get-intrinsic "^1.1.3"
     is-string "^1.0.7"
 
+array-move@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.npmmirror.com/array-move/-/array-move-3.0.1.tgz#179645cc0987b65953a4fc06b6df9045e4ba9618"
+  integrity sha512-H3Of6NIn2nNU1gsVDqDnYKY/LCdWvCMMOWifNGhKcVQgiZ6nOek39aESOvro6zmueP07exSl93YLvkN4fZOkSg==
+
 array-tree-filter@^2.1.0:
   version "2.1.0"
   resolved "https://registry.npmmirror.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190"
@@ -5245,6 +5250,11 @@ image-size@~0.5.0:
   resolved "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
   integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
 
+immediate@~3.0.5:
+  version "3.0.6"
+  resolved "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
+  integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
+
 immer@^8.0.4:
   version "8.0.4"
   resolved "https://registry.npmmirror.com/immer/-/immer-8.0.4.tgz#3a21605a4e2dded852fb2afd208ad50969737b7a"
@@ -5812,6 +5822,16 @@ jsonfile@^6.0.1:
     array-includes "^3.1.5"
     object.assign "^4.1.3"
 
+jszip@^3.5.0:
+  version "3.10.1"
+  resolved "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2"
+  integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==
+  dependencies:
+    lie "~3.3.0"
+    pako "~1.0.2"
+    readable-stream "~2.3.6"
+    setimmediate "^1.0.5"
+
 kind-of@^6.0.2, kind-of@^6.0.3:
   version "6.0.3"
   resolved "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
@@ -5852,6 +5872,13 @@ levn@^0.4.1:
     prelude-ls "^1.2.1"
     type-check "~0.4.0"
 
+lie@~3.3.0:
+  version "3.3.0"
+  resolved "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"
+  integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
+  dependencies:
+    immediate "~3.0.5"
+
 lilconfig@2.0.6:
   version "2.0.6"
   resolved "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4"
@@ -6506,7 +6533,7 @@ p-try@^2.0.0:
   resolved "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
   integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
 
-pako@~1.0.5:
+pako@~1.0.2, pako@~1.0.5:
   version "1.0.11"
   resolved "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
   integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
@@ -7919,7 +7946,7 @@ read-pkg@^5.2.0:
     parse-json "^5.0.0"
     type-fest "^0.6.0"
 
-readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6:
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
   version "2.3.7"
   resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
   integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@@ -8290,7 +8317,7 @@ semver@^7.3.4, semver@^7.3.5, semver@^7.3.7:
   dependencies:
     lru-cache "^6.0.0"
 
-setimmediate@^1.0.4:
+setimmediate@^1.0.4, setimmediate@^1.0.5:
   version "1.0.5"
   resolved "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
   integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==