This is an automated email from the ASF dual-hosted git repository.

hefengen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 89d93bb5 [Task] Export and Import Current Configurations #402 (#403)
89d93bb5 is described below

commit 89d93bb51f02a94b1410a21f921b26ac78d936db
Author: aias00 <[email protected]>
AuthorDate: Thu Mar 14 22:32:33 2024 +0800

    [Task] Export and Import Current Configurations #402 (#403)
    
    * Export and Import Current Configurations #402
    
    * Export and Import Current Configurations #402
    
    * Export and Import Current Configurations #402
    
    * Export and Import Current Configurations #402
---
 src/locales/en-US.json               |   7 +
 src/locales/zh-CN.json               |  16 +-
 src/models/common.js                 |  61 ++--
 src/routes/Home/AddModal.js          | 106 ++++++
 src/routes/Home/ImportResultModal.js | 108 +++++++
 src/routes/Home/index.js             | 112 +++++--
 src/services/api.js                  | 607 ++++++++++++++++++-----------------
 src/utils/download.js                |  63 ++++
 8 files changed, 745 insertions(+), 335 deletions(-)

diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index a48e9021..39f49b1d 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -47,6 +47,7 @@
   "SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS": "Update Success",
   "SHENYU.COMMON.RESPONSE.DELETE.SUCCESS": "Delete Success",
   "SHENYU.COMMON.RESPONSE.SYNC.SUCCESS": "Sync Success",
+  "SHENYU.COMMON.RESPONSE.EXPORT.SUCCESS": "Export Success",
   "SHENYU.COMMON.RESPONSE.REFRESH.SUCCESS": "Refresh Success",
   "SHENYU.COMMON.WARN.INPUT_SELECTOR": "Please add selector first",
   "SHENYU.COMMON.WARN.INPUT_NUMBER": "Please enter number",
@@ -364,6 +365,12 @@
   "SHENYU.DOCUMENT.TAG.TABLE.CREATETIME": "Create Time",
   "SHENYU.DOCUMENT.TAG.TABLE.MODIFYTIME": "Modify Time",
   "SHENYU.COMMON.REQUIRED": "Required",
+  "SHENYU.COMMON.EXPORT": "Export All Config",
+  "SHENYU.COMMON.IMPORT": "Import Configs",
+  "SHENYU.COMMON.IMPORT.RESULT": "Import Result",
+  "SHENYU.COMMON.IMPORT.METADATA.RESULT": "meta import fail message",
+  "SHENYU.COMMON.IMPORT.METADATA.COUNT": "meta import success count",
+  "SHENYU.COMMON.UPLOAD": "Click to Upload",
   "SHENYU.COMMON.MAX.LENGTH": "Max Length",
   "SHENYU.COMMON.MAX.EXAMPLE": "Example",
   "SHENYU.COMMON.MAX.ENVIRONMENT": "Environment",
diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json
index 369f9913..d3b8ed47 100644
--- a/src/locales/zh-CN.json
+++ b/src/locales/zh-CN.json
@@ -4,7 +4,8 @@
   "SHENYU.GLOBALHEADER.CHANGE.PASSWORD": "修改密码",
   "SHENYU.GLOBALHEADER.NEW.PASSWORD": "新密码",
   "SHENYU.GLOBALHEADER.OLD.PASSWORD": "旧密码",
-  "SHENYU.GLOBALHEADER.PASSWORD.EXTRA": "长度至少为8,包含大小写字母、数字和特殊字符",
+  "SHENYU.GLOBALHEADER.PASSWORD.EXTRA":
+    "长度至少为8,包含大小写字母、数字和特殊字符",
   "SHENYU.GLOBALHEADER.PASSWORD.REQUIRED": "请输入新密码",
   "SHENYU.GLOBALHEADER.PASSWORD.LENGTH": "密码长度为8~16个字符",
   "SHENYU.GLOBALHEADER.PASSWORD.RULE":
@@ -44,6 +45,7 @@
   "SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS": "修改成功",
   "SHENYU.COMMON.RESPONSE.DELETE.SUCCESS": "删除成功",
   "SHENYU.COMMON.RESPONSE.SYNC.SUCCESS": "同步成功",
+  "SHENYU.COMMON.RESPONSE.EXPORT.SUCCESS": "导出成功",
   "SHENYU.COMMON.RESPONSE.REFRESH.SUCCESS": "刷新成功",
   "SHENYU.COMMON.WARN.INPUT_SELECTOR": "请先添加选择器",
   "SHENYU.COMMON.WARN.INPUT_NUMBER": "请输入数字",
@@ -330,7 +332,8 @@
   "SHENYU.DOCUMENT.APIDOC.INFO.COMMON.RESPONSE.PARAMETERS": "公共响应参数",
   "SHENYU.DOCUMENT.APIDOC.INFO.COMMON.RESPONSE.CODE": "返回码",
   "SHENYU.DOCUMENT.APIDOC.INFO.COMMON.RESPONSE.DESCRIPTION": "错误描述信息",
-  "SHENYU.DOCUMENT.APIDOC.INFO.COMMON.RESPONSE.DESCRIPTION_EXAMPLE": "非法的参数",
+  "SHENYU.DOCUMENT.APIDOC.INFO.COMMON.RESPONSE.DESCRIPTION_EXAMPLE":
+    "非法的参数",
   "SHENYU.DOCUMENT.APIDOC.INFO.COMMON.RESPONSE.RESULTS": "响应的业务结果",
   "SHENYU.DOCUMENT.APIDOC.INFO.BUSINESS.RESPONSE.PARAMETERS": "业务响应参数",
   "SHENYU.DOCUMENT.APIDOC.INFO.INTERFACE.DEBUG": "接口调试",
@@ -367,6 +370,12 @@
   "SHENYU.DOCUMENT.TAG.TABLE.CREATETIME": "创建时间",
   "SHENYU.DOCUMENT.TAG.TABLE.MODIFYTIME": "修改时间",
   "SHENYU.COMMON.REQUIRED": "必填",
+  "SHENYU.COMMON.EXPORT": "导出所有配置",
+  "SHENYU.COMMON.IMPORT": "导入配置",
+  "SHENYU.COMMON.IMPORT.RESULT": "导入结果",
+  "SHENYU.COMMON.IMPORT.METADATA.RESULT": "元数据导入失败信息",
+  "SHENYU.COMMON.IMPORT.METADATA.COUNT": "元数据导入成功数量",
+  "SHENYU.COMMON.UPLOAD": "点击上传",
   "SHENYU.COMMON.MAX.LENGTH": "最大长度",
   "SHENYU.COMMON.MAX.EXAMPLE": "示例值",
   "SHENYU.COMMON.MAX.ENVIRONMENT": "环境类型",
@@ -390,7 +399,8 @@
   "SHENYU.DISCOVERY.CONFIGURATION.NAME": "名称",
   "SHENYU.DISCOVERY.CONFIGURATION.NAME.INPUT": "请填写服务发现名称",
   "SHENYU.DISCOVERY.CONFIGURATION.SERVERLIST": "服务器列表",
-  "SHENYU.DISCOVERY.CONFIGURATION.SERVERLIST.INPUT": "请填写注册服务器URL,以逗号分隔",
+  "SHENYU.DISCOVERY.CONFIGURATION.SERVERLIST.INPUT":
+    "请填写注册服务器URL,以逗号分隔",
   "SHENYU.DISCOVERY.CONFIGURATION.PROPS": "服务发现属性",
   "SHENYU.DISCOVERY.CONFIGURATION.PROPS.INPUT": "请填写服务发现的属性",
   "SHENYU.DISCOVERY.CONFIGURATION.DELETE": "确定删除该插件级别服务发现配置吗?",
diff --git a/src/models/common.js b/src/models/common.js
index db1ae7f0..648b0fc5 100644
--- a/src/models/common.js
+++ b/src/models/common.js
@@ -28,8 +28,10 @@ import {
   deleteRule,
   findRule,
   updateRule,
+  asyncConfigExport,
+  asyncConfigImport,
 } from "../services/api";
-import {getIntlContent} from "../utils/IntlUtils";
+import { getIntlContent } from "../utils/IntlUtils";
 
 export default {
   namespace: "common",
@@ -43,7 +45,7 @@ export default {
   },
 
   effects: {
-    *fetchSelector({ payload }, { call, put }) {
+    *fetchSelector ({ payload }, { call, put }) {
       const json = yield call(getAllSelectors, { ...payload });
       if (json.code === 200) {
         let { page, dataList } = json.data;
@@ -87,7 +89,7 @@ export default {
       }
 
     },
-    *fetchRule({ payload }, { call, put }) {
+    *fetchRule ({ payload }, { call, put }) {
       const json = yield call(getAllRules, payload);
       if (json.code === 200) {
         let { page, dataList } = json.data;
@@ -104,7 +106,7 @@ export default {
         });
       }
     },
-    *addSelector(params, { call, put }) {
+    *addSelector (params, { call, put }) {
       const { payload, callback, fetchValue } = params;
       const json = yield call(addSelector, payload);
       if (json.code === 200) {
@@ -117,7 +119,7 @@ export default {
       }
     },
 
-    *addRule(params, { call, put }) {
+    *addRule (params, { call, put }) {
       const { payload, callback, fetchValue } = params;
       const json = yield call(addRule, payload);
       if (json.code === 200) {
@@ -129,7 +131,7 @@ export default {
       }
     },
 
-    *fetchSeItem(params, { call }) {
+    *fetchSeItem (params, { call }) {
       const { payload, callback } = params;
       const json = yield call(findSelector, payload);
       if (json.code === 200) {
@@ -137,7 +139,7 @@ export default {
         callback(selector);
       }
     },
-    *deleteSelector(params, { call, put }) {
+    *deleteSelector (params, { call, put }) {
       const { payload, fetchValue } = params;
       const { list } = payload;
       const json = yield call(deleteSelector, { list });
@@ -155,7 +157,7 @@ export default {
         message.warn(json.message);
       }
     },
-    *updateSelector(params, { call, put }) {
+    *updateSelector (params, { call, put }) {
       const { payload, callback, fetchValue } = params;
       const json = yield call(updateSelector, payload);
       if (json.code === 200) {
@@ -166,7 +168,7 @@ export default {
         message.warn(json.message);
       }
     },
-    *deleteRule(params, { call, put }) {
+    *deleteRule (params, { call, put }) {
       const { payload, fetchValue } = params;
       const { list } = payload;
       const json = yield call(deleteRule, { list });
@@ -177,7 +179,7 @@ export default {
         message.warn(json.message);
       }
     },
-    *fetchRuleItem(params, { call }) {
+    *fetchRuleItem (params, { call }) {
       const { payload, callback } = params;
       const json = yield call(findRule, payload);
       if (json.code === 200) {
@@ -185,7 +187,7 @@ export default {
         callback(rule);
       }
     },
-    *updateRule(params, { call, put }) {
+    *updateRule (params, { call, put }) {
       const { payload, callback, fetchValue } = params;
       const json = yield call(updateRule, payload);
       if (json.code === 200) {
@@ -197,23 +199,44 @@ export default {
       }
     },
 
-    *reload(params, { put }) {
+    *reload (params, { put }) {
       const { fetchValue } = params;
       const { pluginId, currentPage, pageSize } = fetchValue;
       const payload = { pluginId, currentPage, pageSize };
       yield put({ type: "fetchSelector", payload });
     },
 
-    *reloadRule(params, { put }) {
+    *reloadRule (params, { put }) {
       const { fetchValue } = params;
       const { selectorId, currentPage, pageSize } = fetchValue;
       const payload = { selectorId, currentPage, pageSize };
       yield put({ type: "fetchRule", payload });
-    }
+    },
+
+    *exportAll (_, { call }) {
+      yield call(asyncConfigExport);
+    },
+
+    *import (params, { call }) {
+      const { payload, callback } = params;
+      const json = yield call(asyncConfigImport, payload);
+      if (json.code === 200) {
+        if (json.data === null) {
+          
message.success(getIntlContent('SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS'));
+          callback();
+        } else {
+          // message.warn(JSON.stringify(json.data));
+          callback(JSON.stringify(json.data));
+        }
+      } else {
+        message.warn(json.message);
+      }
+    },
+
   },
 
   reducers: {
-    saveSelector(state, { payload }) {
+    saveSelector (state, { payload }) {
       return {
         ...state,
         selectorList: payload.selectorList,
@@ -221,27 +244,27 @@ export default {
       };
     },
 
-    saveRule(state, { payload }) {
+    saveRule (state, { payload }) {
       return {
         ...state,
         ruleList: payload.ruleList,
         ruleTotal: payload.ruleTotal
       };
     },
-    saveCurrentSelector(state, { payload }) {
+    saveCurrentSelector (state, { payload }) {
       return {
         ...state,
         currentSelector: payload.currentSelector
       };
     },
-    resetData() {
+    resetData () {
       return {
         selectorList: [],
         ruleList: [],
         selectorTotal: 0,
         ruleTotal: 0,
         currentSelector: ""
-      }
+      };
     }
   }
 };
diff --git a/src/routes/Home/AddModal.js b/src/routes/Home/AddModal.js
new file mode 100644
index 00000000..212c43d4
--- /dev/null
+++ b/src/routes/Home/AddModal.js
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { Component, forwardRef, Fragment } from "react";
+import { Modal, Form, Button } from "antd";
+import { connect } from "dva";
+import { getIntlContent } from "../../utils/IntlUtils";
+
+
+const FormItem = Form.Item;
+const ChooseFile = forwardRef(({ onChange, file }, ref) => {
+  const handleFileInput = (e) => {
+    onChange(e.target.files[0]);
+  };
+  return (
+    <>
+
+      <Button onClick={() => { document.getElementById("file").click(); 
}}>{getIntlContent("SHENYU.COMMON.UPLOAD")}</Button> {file?.name}
+      <input ref={ref} type="file" onChange={handleFileInput} style={{ 
display: 'none' }} id="file" />
+    </>
+  );
+});
+@connect(({ global }) => ({
+  platform: global.platform
+}))
+class AddModal extends Component {
+  handleSubmit = e => {
+    const { form, handleOk } = this.props;
+    e.preventDefault();
+    form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        let { file } = values;
+        handleOk({ file });
+      }
+    });
+  };
+
+  render () {
+    let {
+      handleCancel,
+      form,
+      config,
+      file
+    } = this.props;
+    const { getFieldDecorator } = form;
+    const formItemLayout = {
+      labelCol: {
+        sm: { span: 7 }
+      },
+      wrapperCol: {
+        sm: { span: 17 }
+      }
+    };
+    if (config) {
+      config = JSON.parse(config);
+    }
+
+    return (
+      <Modal
+        width={520}
+        centered
+        title={getIntlContent("SHENYU.COMMON.IMPORT")}
+        visible
+        okText={getIntlContent("SHENYU.COMMON.SURE")}
+        cancelText={getIntlContent("SHENYU.COMMON.CALCEL")}
+        onOk={this.handleSubmit}
+        onCancel={handleCancel}
+      >
+        <Form onSubmit={this.handleSubmit} className="login-form">
+          <FormItem
+            {...formItemLayout}
+            label={getIntlContent("SHENYU.COMMON.IMPORT")}
+          >
+            {getFieldDecorator("file", {
+              rules: [
+                {
+                  required: true,
+                }
+              ],
+              initialValue: file,
+              valuePropName: "file"
+            })(<ChooseFile />)
+
+            }
+          </FormItem>
+        </Form>
+      </Modal>
+    );
+  }
+}
+
+export default Form.create()(AddModal);
diff --git a/src/routes/Home/ImportResultModal.js 
b/src/routes/Home/ImportResultModal.js
new file mode 100644
index 00000000..70d96dbf
--- /dev/null
+++ b/src/routes/Home/ImportResultModal.js
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { Component } from "react";
+import { Modal, Form, Tooltip } from "antd";
+import { connect } from "dva";
+import { getIntlContent } from "../../utils/IntlUtils";
+
+const keyMap = {
+  metaImportSuccessCount: 'metaImportSuccessCount',
+  metaImportFailMessage: 'metaImportFailMessage',
+  authImportSuccessCount: 'authImportSuccessCount',
+  authImportFailMessage: 'authImportFailMessage',
+  pluginImportSuccessCount: 'pluginImportSuccessCount',
+  pluginImportFailMessage: 'pluginImportFailMessage',
+  proxySelectorImportSuccessCount: 'proxySelectorImportSuccessCount',
+  proxySelectorImportFailMessage: 'proxySelectorImportFailMessage',
+  discoveryImportSuccessCount: 'discoveryImportSuccessCount',
+  discoveryImportFailMessage: 'discoveryImportFailMessage',
+  discoveryUpstreamImportSuccessCount: 'discoveryUpstreamImportSuccessCount',
+  discoveryUpstreamImportFailMessage: 'discoveryUpstreamImportFailMessage',
+  dictImportSuccessCount: 'dictImportSuccessCount',
+  dictImportFailMessage: 'dictImportFailMessage'
+};
+
+@connect(({ global }) => ({
+  platform: global.platform
+}))
+class ImportResultModal extends Component {
+  handleSubmit = e => {
+    const { form, handleOk } = this.props;
+    e.preventDefault();
+    form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        let { file } = values;
+        handleOk({ file });
+      }
+    });
+  };
+
+  handleRes = (json, key) => {
+    // return data;
+    const data = json[key];
+    const maxLength = 50; // set the max show length
+    if (data && data.length > maxLength) {
+      return (
+        <Tooltip title={data}>
+          {`${data.substring(0, maxLength)}...`}
+        </Tooltip>
+      );
+    }
+    return (
+      <Tooltip title={data}>
+        {data}
+      </Tooltip>
+    );
+  };
+
+  formatKey = (key) => {
+    return keyMap[key] || key;
+  };
+
+  renderContent = (json) => {
+    return Object.keys(keyMap).map((key) => (
+      <p key={key}>
+        <strong>{this.formatKey(key)}:</strong> {this.handleRes(json, key)}
+      </p>
+    ));
+  };
+
+  render () {
+    let {
+      onOk,
+      onCancel,
+      json
+
+    } = this.props;
+
+    return (
+      <Modal
+        title={getIntlContent("SHENYU.COMMON.IMPORT.RESULT")}
+        visible
+        onOk={onOk}
+        onCancel={onCancel}
+      >
+        <pre style={{ whiteSpace: 'pre-wrap', wordWrap: 'break-word' }}>
+          {this.renderContent(json)}
+        </pre>
+      </Modal>
+    );
+  }
+}
+
+export default Form.create()(ImportResultModal);
diff --git a/src/routes/Home/index.js b/src/routes/Home/index.js
index c25164ac..7bdc667a 100644
--- a/src/routes/Home/index.js
+++ b/src/routes/Home/index.js
@@ -16,12 +16,14 @@
  */
 
 import React, { Component } from "react";
-import { Steps, Divider, Card, Col, Row, Timeline, Statistic, Icon, Popover, 
Tag, Alert, Button, Modal } from 'antd';
+import { Button, Steps, Divider, Card, Col, Row, Timeline, Statistic, Icon, 
Popover, Tag, Alert, Modal } from 'antd';
 import { connect } from "dva";
 import { routerRedux } from 'dva/router';
 import styles from "./home.less";
 import { getIntlContent } from '../../utils/IntlUtils';
 import { activePluginSnapshot, getNewEventRecodLogList } from 
"../../services/api";
+import AddModal from "./AddModal";
+import ImportResultModal from "./ImportResultModal";
 
 const { Step } = Steps;
 
@@ -39,10 +41,11 @@ export default class Home extends Component {
       localeName: '',
       activePluginSnapshot: [],
       activeLog: [],
-    }
+      popup: "",
+    };
   }
 
-  componentDidMount() {
+  componentDidMount () {
     const token = window.sessionStorage.getItem("token");
     if (token) {
       const { dispatch } = this.props;
@@ -52,25 +55,25 @@ export default class Home extends Component {
     }
     activePluginSnapshot().then(res => {
       if (res) {
-        this.setState({ activePluginSnapshot: res.data || [] })
+        this.setState({ activePluginSnapshot: res.data || [] });
       }
     });
     getNewEventRecodLogList().then(res => {
       if (res) {
-        this.setState({ activeLog: res.data || [] })
+        this.setState({ activeLog: res.data || [] });
       }
-    })
+    });
 
   }
 
-  componentWillUnmount() {
+  componentWillUnmount () {
     this.setState = () => false;
   }
 
   pluginOnClick = (plugin) => {
     const { dispatch } = this.props;
     dispatch(routerRedux.push(`plug/${plugin.role}/${plugin.name}`));
-  }
+  };
 
   getEventLogTitle = (log) => {
     const textStyle = { fontWeight: "bold", color: "#4f6eee" };
@@ -80,7 +83,7 @@ export default class Home extends Component {
         <span style={textStyle}>{log.operationType}</span> by <span 
style={textStyle}>{log.operator}</span>
       </div>
     );
-  }
+  };
 
   showEventLogDetail = (log) => {
     Modal.info({
@@ -88,16 +91,70 @@ export default class Home extends Component {
       icon: null,
       width: 500,
       content: (
-        <div style={{ maxHeight: 400, overflowY: 'auto'}}>
+        <div style={{ maxHeight: 400, overflowY: 'auto' }}>
           {log.context}
         </div>
       ),
-      onOk() {},
+      onOk () { },
     });
-  }
+  };
+
+  // 导出数据
+  exportAllClick = () => {
+    const { dispatch } = this.props;
+    dispatch({
+      type: "common/exportAll"
+    });
+  };
+
+  closeModal = (refresh) => {
+    if (refresh) {
+      this.setState({ popup: "" }, this.query);
+    }
+    this.setState({ popup: "" });
+  };
+
+  importConfigClick = () => {
+    this.setState({
+      popup: (
+        <AddModal
+          disabled={false}
+          handleOk={values => {
+            const { dispatch } = this.props;
+            dispatch({
+              type: "common/import",
+              payload: values,
+              callback: (res) => {
+                this.closeModal(true);
+                this.showImportRestlt(JSON.parse(res));
+              }
+            });
+          }}
+          handleCancel={() => {
+            this.closeModal();
+          }}
+        />
+      )
+    });
+  };
+
+  showImportRestlt = (json) => {
+    this.setState({
+      popup: (
+        <ImportResultModal
+          disabled={false}
+          json={json}
+          title={getIntlContent("SHENYU.COMMON.IMPORT.RESULT")}
+          onCancel={() => this.closeModal(true)}
+          onOk={() => this.closeModal(true)}
+        />
+      )
+    });
+  };
 
-  render() {
-    const contextStyle = { "fontWeight": "bold", color: "#3b9a9c" }
+  render () {
+    const { popup } = this.state;
+    const contextStyle = { "fontWeight": "bold", color: "#3b9a9c" };
     const pluginSteps = this.state.activePluginSnapshot.map((p, index) => {
       const content = (
         <div>
@@ -106,7 +163,7 @@ export default class Home extends Component {
           <p>the plugin has selector is : <span 
style={contextStyle}>{p.selectorCount} </span></p>
           <hr />
           <div style={contextStyle}>
-            <pre><code>{JSON.stringify(JSON.parse(p.config  ? p.config : 
'{}'), null, 4)}</code></pre>
+            <pre><code>{JSON.stringify(JSON.parse(p.config ? p.config : '{}'), 
null, 4)}</code></pre>
           </div>
         </div>
       );
@@ -118,7 +175,7 @@ export default class Home extends Component {
       );
       const description = <span>handle is <span 
style={contextStyle}>{p.handleCount}</span>  selector is <span 
style={contextStyle}>{p.selectorCount} </span></span>;
       return <Step title={title} key={index} description={description} />;
-    })
+    });
     const activeLogItems = this.state.activeLog.map((log, index) => {
       const type = log.operationType.startsWith("CREATE") ? "success" : 
log.operationType.startsWith("DELETE") ? "warning" : "info";
       return (
@@ -134,14 +191,32 @@ export default class Home extends Component {
             type={type}
           />
         </Timeline.Item>
-      )
-    })
+      );
+    });
 
     return (
       <div>
         <div className={styles.content}>
           <span style={{ textShadow: '1px 1px 3px' 
}}>{getIntlContent("SHENYU.HOME.WELCOME")}</span>
         </div>
+        <div>
+          <Button
+            style={{ marginLeft: 20, marginBottom: 20 }}
+            icon="export"
+            type="primary"
+            onClick={this.exportAllClick}
+          >
+            {getIntlContent("SHENYU.COMMON.EXPORT")}
+          </Button>
+          <Button
+            style={{ marginLeft: 20, marginBottom: 20 }}
+            icon="import"
+            type="primary"
+            onClick={this.importConfigClick}
+          >
+            {getIntlContent("SHENYU.COMMON.IMPORT")}
+          </Button>
+        </div>
         <div className={styles.processContent}>
           <Steps current={1}>
             <Step title="User Request" />
@@ -227,6 +302,7 @@ export default class Home extends Component {
             </Col>
           </Row>
         </div>
+        {popup}
       </div>
     );
   }
diff --git a/src/services/api.js b/src/services/api.js
index a6d6674d..01580942 100644
--- a/src/services/api.js
+++ b/src/services/api.js
@@ -15,32 +15,33 @@
  * limitations under the License.
  */
 
-import { stringify } from "qs";
-import request from "../utils/request";
+import { stringify } from "qs"
+import request from "../utils/request"
+import download from "../utils/download"
 
-const baseUrl = document.getElementById("httpPath").innerHTML;
+const baseUrl = document.getElementById("httpPath").innerHTML
 
 /* add user */
-export async function addUser(params) {
+export async function addUser (params) {
   return request(`${baseUrl}/dashboardUser`, {
     method: `POST`,
     body: {
       ...params,
       role: 1
     }
-  });
+  })
 }
 
 /* delete user */
-export async function deleteUser(params) {
+export async function deleteUser (params) {
   return request(`${baseUrl}/dashboardUser/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
 /* update user */
-export async function updateUser(params) {
+export async function updateUser (params) {
   return request(`${baseUrl}/dashboardUser/${params.id}`, {
     method: `PUT`,
     body: {
@@ -50,18 +51,18 @@ export async function updateUser(params) {
       enabled: params.enabled,
       role: 1
     }
-  });
+  })
 }
 
 /* check user password */
-export async function checkUserPassword() {
+export async function checkUserPassword () {
   return request(`${baseUrl}/dashboardUser/check/password`, {
-      method: `GET`
-  });
+    method: `GET`
+  })
 }
 
 /* update password */
-export async function updatePassword(params) {
+export async function updatePassword (params) {
   return request(`${baseUrl}/dashboardUser/modify-password/${params.id}`, {
     method: `PUT`,
     body: {
@@ -69,12 +70,12 @@ export async function updatePassword(params) {
       password: params.password,
       oldPassword: params.oldPassword
     }
-  });
+  })
 }
 
 /* get all metadata */
-export async function getAllMetadata(params) {
-  const { path, currentPage, pageSize } = params;
+export async function getAllMetadata (params) {
+  const { path, currentPage, pageSize } = params
   return request(
     `${baseUrl}/meta-data/queryList?${stringify(
       path ? params : { currentPage, pageSize }
@@ -82,27 +83,27 @@ export async function getAllMetadata(params) {
     {
       method: `GET`
     }
-  );
+  )
 }
 
-export async function findMetadata(params) {
+export async function findMetadata (params) {
   return request(`${baseUrl}/meta-data/${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* addMetadata */
-export async function addMetadata(params) {
+export async function addMetadata (params) {
   return request(`${baseUrl}/meta-data/createOrUpdate`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* updateMetadata */
-export async function updateMetadata(params) {
+export async function updateMetadata (params) {
   return request(`${baseUrl}/meta-data/createOrUpdate`, {
     method: `POST`,
     body: {
@@ -117,184 +118,182 @@ export async function updateMetadata(params) {
       rpcType: params.rpcType,
       serviceName: params.serviceName
     }
-  });
+  })
 }
 
 /* syncData */
-export async function syncData() {
+export async function syncData () {
   return request(`${baseUrl}/meta-data/syncData`, {
     method: `POST`,
     body: {}
-  });
+  })
 }
 
 /* getfetchMetaGroup */
-export async function getfetchMetaGroup() {
+export async function getfetchMetaGroup () {
   return request(`${baseUrl}/meta-data/findAllGroup`, {
     method: `GET`
-  });
+  })
 }
 
 /* deleteMetadata */
-export async function deleteMetadata(params) {
+export async function deleteMetadata (params) {
   return request(`${baseUrl}/meta-data/batchDeleted`, {
     method: `POST`,
     body: [...params.list]
-  });
+  })
 }
 
 /* updateEnabled */
-export async function updateEnabled(params) {
+export async function updateEnabled (params) {
   return request(`${baseUrl}/meta-data/batchEnabled`, {
     method: `POST`,
     body: {
       ids: params.list,
       enabled: params.enabled
     }
-  });
+  })
 }
 
 /* getAllUsers */
-export async function getAllUsers(params) {
-  const { userName, currentPage, pageSize } = params;
-  const myParams = userName ? params : { currentPage, pageSize };
+export async function getAllUsers (params) {
+  const { userName, currentPage, pageSize } = params
+  const myParams = userName ? params : { currentPage, pageSize }
   return request(`${baseUrl}/dashboardUser?${stringify(myParams)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* findUser */
-export async function findUser(params) {
+export async function findUser (params) {
   return request(`${baseUrl}/dashboardUser/${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* addPlugin */
-export async function addPlugin(params) {
-  const formData = new FormData();
-  formData.append("name", params.name);
-  if (params.config) formData.append("config", params.config);
-  formData.append("sort", params.sort);
-  formData.append("role", params.role);
-  formData.append("enabled", params.enabled);
+export async function addPlugin (params) {
+  const formData = new FormData()
+  formData.append("name", params.name)
+  if (params.config) formData.append("config", params.config)
+  formData.append("sort", params.sort)
+  formData.append("role", params.role)
+  formData.append("enabled", params.enabled)
   if (params.file) {
-    if(typeof params.file === 'string')
-    {
-      formData.append("file", params.file);
-    }else {
-      const base64Data = await readFileAsBase64(params.file);
-      formData.append("file", base64Data);
+    if (typeof params.file === 'string') {
+      formData.append("file", params.file)
+    } else {
+      const base64Data = await readFileAsBase64(params.file)
+      formData.append("file", base64Data)
     }
   }
   return request(`${baseUrl}/plugin`, {
     method: `POST`,
     body: formData,
-  });
+  })
 }
 
-function readFileAsBase64(file) {
+function readFileAsBase64 (file) {
   return new Promise((resolve, reject) => {
-    const reader = new FileReader();
+    const reader = new FileReader()
 
     reader.onload = (event) => {
-      const base64String = event.target.result.split(",")[1];
-      resolve(base64String);
-    };
+      const base64String = event.target.result.split(",")[1]
+      resolve(base64String)
+    }
 
     reader.onerror = (error) => {
-      reject(error);
-    };
+      reject(error)
+    }
 
-    reader.readAsDataURL(file);
-  });
+    reader.readAsDataURL(file)
+  })
 }
 
 /* deletePlugin */
-export async function deletePlugin(params) {
+export async function deletePlugin (params) {
   return request(`${baseUrl}/plugin/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
 /* updatePlugin */
-export async function updatePlugin(params) {
-  const formData = new FormData;
-  formData.append("ids",params.id);
-  formData.append("name",params.name);
-  if(params.config) formData.append("config",params.config);
-  formData.append("sort",params.sort);
-  formData.append("role",params.role);
-  formData.append("enabled",params.enabled);
-  if (params.file ) {
-    if(typeof params.file === 'string')
-    {
-      formData.append("file", params.file);
-    }else {
-      const base64Data = await readFileAsBase64(params.file);
-      formData.append("file", base64Data);
+export async function updatePlugin (params) {
+  const formData = new FormData
+  formData.append("ids", params.id)
+  formData.append("name", params.name)
+  if (params.config) formData.append("config", params.config)
+  formData.append("sort", params.sort)
+  formData.append("role", params.role)
+  formData.append("enabled", params.enabled)
+  if (params.file) {
+    if (typeof params.file === 'string') {
+      formData.append("file", params.file)
+    } else {
+      const base64Data = await readFileAsBase64(params.file)
+      formData.append("file", base64Data)
     }
   }
   return request(`${baseUrl}/plugin/${params.id}`, {
 
     method: `PUT`,
     body: formData
-  });
+  })
 }
 
 /* getAllPlugins */
-export async function getAllPlugins(params) {
+export async function getAllPlugins (params) {
   return request(`${baseUrl}/plugin?${stringify(params)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* get Plugins snapshot */
-export function activePluginSnapshot() {
+export function activePluginSnapshot () {
   return request(`${baseUrl}/plugin/snapshot/active`, {
     method: `GET`
-  });
+  })
 }
 
 /* findPlugin */
-export async function findPlugin(params) {
+export async function findPlugin (params) {
   return request(`${baseUrl}/plugin/${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* updatepluginEnabled */
-export async function updatepluginEnabled(params) {
+export async function updatepluginEnabled (params) {
   return request(`${baseUrl}/plugin/enabled`, {
     method: `POST`,
     body: {
       ids: params.list,
       enabled: params.enabled
     }
-  });
+  })
 }
 
 /* addAuth */
-export async function addAuth(params) {
+export async function addAuth (params) {
   return request(`${baseUrl}/appAuth`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* deleteAuth */
-export async function deleteAuth(params) {
+export async function deleteAuth (params) {
   return request(`${baseUrl}/appAuth/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
 /* updateAuth */
-export async function updateAuth(params) {
+export async function updateAuth (params) {
   return request(`${baseUrl}/appAuth/${params.id}`, {
     method: `PUT`,
     body: {
@@ -302,201 +301,201 @@ export async function updateAuth(params) {
       appSecret: params.appSecret,
       enabled: params.enabled
     }
-  });
+  })
 }
 
 /* getAllAuth */
-export async function getAllAuth(params) {
-  const { appKey, currentPage, pageSize } = params;
-  let myParams = appKey ? params : { currentPage, pageSize };
+export async function getAllAuth (params) {
+  const { appKey, currentPage, pageSize } = params
+  let myParams = appKey ? params : { currentPage, pageSize }
   return request(`${baseUrl}/appAuth?${stringify(myParams)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* syncAuthsData */
-export async function syncAuthsData() {
+export async function syncAuthsData () {
   return request(`${baseUrl}/appAuth/syncData`, {
     method: `POST`,
     body: {}
-  });
+  })
 }
 
 /* getAllAuths */
-export async function getAllAuths(params) {
-  const { appKey, phone, currentPage, pageSize } = params;
-  const myParams = appKey || phone ? params : { currentPage, pageSize };
+export async function getAllAuths (params) {
+  const { appKey, phone, currentPage, pageSize } = params
+  const myParams = appKey || phone ? params : { currentPage, pageSize }
   return request(`${baseUrl}/appAuth/findPageByQuery?${stringify(myParams)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* findAuthData */
-export async function findAuthData(params) {
+export async function findAuthData (params) {
   return request(`${baseUrl}/appAuth/detail?id=${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* findAuthDataDel */
-export async function findAuthDataDel(params) {
+export async function findAuthDataDel (params) {
   return request(`${baseUrl}/appAuth/detailPath?id=${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* get all metadatas */
-export async function getAllMetadatas() {
+export async function getAllMetadatas () {
   return request(`${baseUrl}/meta-data/findAll`, {
     method: `GET`
-  });
+  })
 }
 
 /* update auth */
-export async function updateAuthData(params) {
+export async function updateAuthData (params) {
   return request(`${baseUrl}/appAuth/updateDetail`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* update authDel */
-export async function updateAuthDel(params) {
+export async function updateAuthDel (params) {
   return request(`${baseUrl}/appAuth/updateDetailPath`, {
     method: `POST`,
     body: params
-  });
+  })
 }
 
 /* add auth */
-export async function addAuthData(params) {
+export async function addAuthData (params) {
   return request(`${baseUrl}/appAuth/apply`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* batch enable auth */
-export async function updateAuthEnabled(params) {
+export async function updateAuthEnabled (params) {
   return request(`${baseUrl}/appAuth/batchEnabled`, {
     method: `POST`,
     body: {
       ids: params.list,
       enabled: params.enabled
     }
-  });
+  })
 }
 
 /* batch delete auth */
-export async function deleteAuths(params) {
+export async function deleteAuths (params) {
   return request(`${baseUrl}/appAuth/batchDelete`, {
     method: `POST`,
     body: [...params.list]
-  });
+  })
 }
 
 /* find auth */
-export async function findAuth(params) {
+export async function findAuth (params) {
   return request(`${baseUrl}/appAuth/${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* add selector */
-export async function addSelector(params) {
+export async function addSelector (params) {
   return request(`${baseUrl}/selector`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* delete selector */
-export async function deleteSelector(params) {
+export async function deleteSelector (params) {
   return request(`${baseUrl}/selector/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
 /* update selector */
-export async function updateSelector(params) {
+export async function updateSelector (params) {
   return request(`${baseUrl}/selector/${params.id}`, {
     method: `PUT`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* get all selectors */
-export async function getAllSelectors(params) {
+export async function getAllSelectors (params) {
   return request(`${baseUrl}/selector?${stringify(params)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* get single selector */
-export async function findSelector(params) {
+export async function findSelector (params) {
   return request(`${baseUrl}/selector/${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
-export async function getAllRules(params) {
+export async function getAllRules (params) {
   return request(`${baseUrl}/rule?${stringify(params)}`, {
     method: `GET`
-  });
+  })
 }
 
-export async function addRule(params) {
+export async function addRule (params) {
   return request(`${baseUrl}/rule`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
-export async function deleteRule(params) {
+export async function deleteRule (params) {
   return request(`${baseUrl}/rule/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
-export async function findRule(params) {
+export async function findRule (params) {
   return request(`${baseUrl}/rule/${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
-export async function updateRule(params) {
+export async function updateRule (params) {
   return request(`${baseUrl}/rule/${params.id}`, {
     method: `PUT`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* query constants */
-export async function queryPlatform() {
+export async function queryPlatform () {
   return request(`${baseUrl}/platform/enum`, {
     method: `GET`
-  });
+  })
 }
 
 /* login */
-export async function queryLogin(params) {
+export async function queryLogin (params) {
   return request(`${baseUrl}/platform/login?${stringify(params)}`, {
     method: `GET`
-  });
+  })
 }
 
 export async function querySecretInfo() {
@@ -506,189 +505,207 @@ export async function querySecretInfo() {
 }
 
 // sync all plugin
-export async function asyncPlugin() {
+export async function asyncPlugin () {
   return request(`${baseUrl}/plugin/syncPluginAll`, {
     method: `POST`
-  });
+  })
+}
+
+// export all config
+export async function asyncConfigExport () {
+  return download(`${baseUrl}/configs/export`, {
+    method: `GET`
+  })
 }
 
+// import configs
+export async function asyncConfigImport (params) {
+  const formData = new FormData()
+  formData.append("file", params.file)
+  return request(`${baseUrl}/configs/import`, {
+    method: `POST`,
+    body: formData,
+  })
+}
+
+
 // 同步单个插件
-export async function asyncOnePlugin(params) {
+export async function asyncOnePlugin (params) {
   return request(`${baseUrl}/plugin/syncPluginData/${params.id}`, {
     method: `PUT`
-  });
+  })
 }
 
 // get plugin dropdown list
-export async function getPluginDropDownList() {
+export async function getPluginDropDownList () {
   return request(`${baseUrl}/plugin/all`, {
     method: `GET`
-  });
+  })
 }
 
 // get plugin handle list
-export async function getAllPluginHandles(params) {
+export async function getAllPluginHandles (params) {
   return request(`${baseUrl}/plugin-handle?${stringify(params)}`, {
     method: `GET`
-  });
+  })
 }
 
 // add plugin handle
-export async function addPluginHandle(params) {
+export async function addPluginHandle (params) {
   return request(`${baseUrl}/plugin-handle`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 // get detail of plugin handle
-export async function findPluginHandle(params) {
+export async function findPluginHandle (params) {
   return request(`${baseUrl}/plugin-handle/${params.id}`, {
     method: "GET"
-  });
+  })
 }
 
 // update PluginHandle
-export async function updatePluginHandle(params) {
+export async function updatePluginHandle (params) {
   return request(`${baseUrl}/plugin-handle/${params.id}`, {
     method: `PUT`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 // batchDeletePluginHandle
-export async function batchDeletePluginHandle(params) {
+export async function batchDeletePluginHandle (params) {
   return request(`${baseUrl}/plugin-handle/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
-export function fetchPluginHandleByPluginId(params) {
+export function fetchPluginHandleByPluginId (params) {
   return request(
     `${baseUrl}/plugin-handle/all/${params.pluginId}/${params.type}`,
     {
       method: `GET`
     }
-  );
+  )
 }
 
 // create plugin resource
-export function addPluginResource(params) {
+export function addPluginResource (params) {
   return request(`${baseUrl}/plugin/createPluginResource/${params.id}`, {
     method: `PUT`,
     body: params
-  });
+  })
 }
 
 // fetch dict list
-export async function fetchShenYuDicts(params) {
+export async function fetchShenYuDicts (params) {
   return request(`${baseUrl}/shenyu-dict?${stringify(params)}`, {
     method: `GET`
-  });
+  })
 }
 
 // add dict
-export async function addShenYuDict(params) {
+export async function addShenYuDict (params) {
   return request(`${baseUrl}/shenyu-dict`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 // get dict detail
-export async function findShenYuDict(params) {
+export async function findShenYuDict (params) {
   return request(`${baseUrl}/shenyu-dict/${params.id}`, {
     method: "GET"
-  });
+  })
 }
 
 // update dict
-export async function updateShenYuDict(params) {
+export async function updateShenYuDict (params) {
   return request(`${baseUrl}/shenyu-dict/${params.id}`, {
     method: `PUT`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 // batch delete dicts
-export async function batchDeleteShenYuDict(params) {
+export async function batchDeleteShenYuDict (params) {
   return request(`${baseUrl}/shenyu-dict/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
-export function fetchShenYuDictByType(params) {
+export function fetchShenYuDictByType (params) {
   return request(`${baseUrl}/shenyu-dict/all/${params.type}`, {
     method: `GET`
-  });
+  })
 }
 
-export async function updateShenYuDictEnabled(params) {
+export async function updateShenYuDictEnabled (params) {
   return request(`${baseUrl}/shenyu-dict/batchEnabled`, {
     method: `POST`,
     body: {
       ids: params.list,
       enabled: params.enabled
     }
-  });
+  })
 }
 
 /* get all roles */
-export async function getAllRoles() {
+export async function getAllRoles () {
   return request(`${baseUrl}/role/getAllRoles`, {
     method: `GET`
-  });
+  })
 }
 
 /* get roles by page */
-export async function getRoleList(params) {
-  const { roleName, currentPage, pageSize } = params;
-  let myParams = { ...params };
+export async function getRoleList (params) {
+  const { roleName, currentPage, pageSize } = params
+  let myParams = { ...params }
   if (!roleName) {
-    myParams = { currentPage, pageSize };
+    myParams = { currentPage, pageSize }
   }
   return request(`${baseUrl}/role?${stringify(myParams)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* find role */
-export async function findRole(params) {
+export async function findRole (params) {
   return request(`${baseUrl}/role/${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* add role */
-export async function addRole(params) {
+export async function addRole (params) {
   return request(`${baseUrl}/role`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* delete role */
-export async function deleteRole(params) {
+export async function deleteRole (params) {
   return request(`${baseUrl}/role/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
 /* update role */
-export async function updateRole(params) {
+export async function updateRole (params) {
   return request(`${baseUrl}/role/${params.id}`, {
     method: `PUT`,
     body: {
@@ -696,232 +713,232 @@ export async function updateRole(params) {
       description: params.description,
       currentPermissionIds: params.currentPermissionIds
     }
-  });
+  })
 }
 
 /* get resources by page */
-export async function getAllResources(params) {
-  const { title, currentPage, pageSize } = params;
-  let myParams = { ...params };
+export async function getAllResources (params) {
+  const { title, currentPage, pageSize } = params
+  let myParams = { ...params }
   if (!title) {
-    myParams = { currentPage, pageSize };
+    myParams = { currentPage, pageSize }
   }
   return request(`${baseUrl}/resource?${stringify(myParams)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* find resource */
-export async function findResource(params) {
+export async function findResource (params) {
   return request(`${baseUrl}/resource/${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* add resource */
-export async function addResource(params) {
+export async function addResource (params) {
   return request(`${baseUrl}/resource`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* delete resource */
-export async function deleteResource(params) {
+export async function deleteResource (params) {
   return request(`${baseUrl}/resource/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
 /* update resource */
-export async function updateResource(params) {
+export async function updateResource (params) {
   return request(`${baseUrl}/resource/${params.id}`, {
     method: `PUT`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* get buttons by menuId */
-export async function getButtons(params) {
+export async function getButtons (params) {
   return request(`${baseUrl}/resource/button?id=${params.id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* get menu tree */
-export async function getMenuTree() {
+export async function getMenuTree () {
   return request(`${baseUrl}/resource/menu`, {
     method: `GET`
-  });
+  })
 }
 
 // get userPermission by token
-export async function getUserPermissionByToken(params) {
+export async function getUserPermissionByToken (params) {
   return request(
     `${baseUrl}/permission/getUserPermissionByToken?token=${params.token}`,
     {
       method: `GET`
     }
-  );
+  )
 }
 
 /* get dataPermision's selectors by page */
-export async function getDataPermisionSelectors(params) {
+export async function getDataPermisionSelectors (params) {
   return request(`${baseUrl}/data-permission/selector?${stringify(params)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* get dataPermision's rules by page */
-export async function getDataPermisionRules(params) {
+export async function getDataPermisionRules (params) {
   return request(`${baseUrl}/data-permission/rules?${stringify(params)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* add dataPermision's selector */
-export async function addDataPermisionSelector(params) {
+export async function addDataPermisionSelector (params) {
   return request(`${baseUrl}/data-permission/selector`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* add dataPermision's rule */
-export async function addDataPermisionRule(params) {
+export async function addDataPermisionRule (params) {
   return request(`${baseUrl}/data-permission/rule`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 // Can't perform a React state update on an unmounted component. This is a 
no-op, but it indicates a memory leak in your application. To fix, cancel all 
subscriptions and
 /* delete dataPermision's selector */
-export async function deleteDataPermisionSelector(params) {
+export async function deleteDataPermisionSelector (params) {
   return request(`${baseUrl}/data-permission/selector`, {
     method: `DELETE`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* delete dataPermision's rule */
-export async function deleteDataPermisionRule(params) {
+export async function deleteDataPermisionRule (params) {
   return request(`${baseUrl}/data-permission/rule`, {
     method: `DELETE`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* get new event recode logs */
-export function getNewEventRecodLogList() {
+export function getNewEventRecodLogList () {
   return request(`${baseUrl}/operation-record/log/list`, {
     method: `GET`
-  });
+  })
 }
 
 /* get all api */
-export function getDocMenus() {
+export function getDocMenus () {
   return request(`${baseUrl}/apidoc/getDocMenus`, {
     method: `GET`
-  });
+  })
 }
 
 /* get api item */
-export function getDocItem(params) {
+export function getDocItem (params) {
   return request(`${baseUrl}/apidoc/getDocItem?${stringify(params)}`, {
     method: `GET`
-  });
+  })
 }
 
 /* sandbox proxyGateway */
-export function sandboxProxyGateway() {
-  return `${baseUrl}/sandbox/proxyGateway`;
+export function sandboxProxyGateway () {
+  return `${baseUrl}/sandbox/proxyGateway`
 }
 
-export function getRootTag() {
+export function getRootTag () {
   return request(`${baseUrl}/tag/queryRootTag`, {
     method: `GET`
-  });
+  })
 }
 
 /* getParentTagId */
-export function getParentTagId(id) {
+export function getParentTagId (id) {
   return request(`${baseUrl}/tag/parentTagId/${id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* getTagDetail */
-export function getTagDetail(id) {
+export function getTagDetail (id) {
   return request(
     `${baseUrl}/tag/id/${id}`, {
-      method: `GET`
-    });
+    method: `GET`
+  })
 }
 
 /** add tag */
-export function addTag(params) {
+export function addTag (params) {
   return request(`${baseUrl}/tag`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /** delete tag */
-export function deleteTag(params) {
+export function deleteTag (params) {
   return request(`${baseUrl}/tag/batchDelete`, {
     method: `DELETE`,
     body: params
-  });
+  })
 }
 
 /** updateTag */
-export function updateTag(params) {
+export function updateTag (params) {
   return request(`${baseUrl}/tag/id/${params.id}`, {
     method: `PUT`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /* queryApi */
-export function getApi(tagId) {
+export function getApi (tagId) {
   return request(`${baseUrl}/api?tagId=${tagId}&currentPage=0&pageSize=100`, {
     method: `GET`
-  });
+  })
 }
 
 /* queryApi */
-export function getApiDetail(id) {
+export function getApiDetail (id) {
   return request(`${baseUrl}/api/${id}`, {
     method: `GET`
-  });
+  })
 }
 
 /* queryMockRequest */
-export function getApiMockRequest(apiId) {
+export function getApiMockRequest (apiId) {
   return request(`${baseUrl}/mock/${apiId}`, {
     method: `GET`
-  });
+  })
 }
 
 /* createOrUpdateMockRequest */
-export function createOrUpdateMockRequest(params) {
+export function createOrUpdateMockRequest (params) {
   return request(`${baseUrl}/mock/insertOrUpdate`, {
     method: `POST`,
     body: {
@@ -931,177 +948,177 @@ export function createOrUpdateMockRequest(params) {
 }
 
 /* createOrUpdateMockRequest */
-export function deleteMockRequest(id) {
+export function deleteMockRequest (id) {
   return request(`${baseUrl}/mock/${id}`, {
     method: `DELETE`
   })
 }
 
 /** addApi */
-export function addApi(params) {
+export function addApi (params) {
   return request(`${baseUrl}/api`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /** addApi */
-export function updateApi(params) {
+export function updateApi (params) {
   return request(`${baseUrl}/api/${params.id}`, {
     method: `PUT`,
     body: {
       ...params
     }
-  });
+  })
 }
 
 /** delete Api */
-export function deleteApi(params) {
+export function deleteApi (params) {
   return request(`${baseUrl}/api/batch`, {
     method: `DELETE`,
     body: params
-  });
+  })
 }
 
-export function fetchProxySelector(params) {
+export function fetchProxySelector (params) {
   return request(`${baseUrl}/proxy-selector?${stringify(params)}`,
     {
       method: `GET`
-    });
+    })
 }
 
-export function addProxySelector(params) {
+export function addProxySelector (params) {
   return request(`${baseUrl}/proxy-selector/addProxySelector`,
     {
       method: `POST`,
       body: params
-    });
+    })
 }
 
-export function deleteProxySelector(params) {
+export function deleteProxySelector (params) {
   return request(`${baseUrl}/proxy-selector/batch`,
     {
       method: `DELETE`,
       body: [...params.list]
-    });
+    })
 }
 
-export function updateProxySelector(params) {
+export function updateProxySelector (params) {
   return request(`${baseUrl}/proxy-selector/${params.id}`,
     {
       method: `PUT`,
       body: {
         ...params
       }
-    });
+    })
 }
 
-export function getDiscoveryTypeEnums() {
+export function getDiscoveryTypeEnums () {
   return request(`${baseUrl}/discovery/typeEnums`,
     {
       method: `GET`
-    });
+    })
 }
 
-export function postDiscoveryInsertOrUpdate(params) {
+export function postDiscoveryInsertOrUpdate (params) {
   return request(`${baseUrl}/discovery/insertOrUpdate`,
     {
       method: `POST`,
       body: params
-    });
+    })
 }
 
-export function getDiscovery(params) {
+export function getDiscovery (params) {
   return request(`${baseUrl}/discovery?${stringify(params)}`,
     {
       method: `GET`
-    });
+    })
 }
 
-export function refreshProxySelector(params) {
+export function refreshProxySelector (params) {
   return 
request(`${baseUrl}/proxy-selector/fetch/${params.discoveryHandlerId}`,
     {
       method: `PUT`,
       body: {
         ...params
       }
-    });
+    })
 }
 
-export function deleteDiscovery(params) {
+export function deleteDiscovery (params) {
   return request(`${baseUrl}/discovery/${params.discoveryId}`,
     {
       method: `DELETE`,
       body: {
         ...params
       }
-    });
+    })
 }
 
-export function getAlertReceivers(params) {
+export function getAlertReceivers (params) {
   return request(`${baseUrl}/alert/receiver?${stringify(params)}`,
     {
       method: `GET`
-    });
+    })
 }
 
-export function getAlertReceiverDetail(params) {
+export function getAlertReceiverDetail (params) {
   return request(`${baseUrl}/alert/receiver/${params.id}`,
     {
       method: `GET`
-    });
+    })
 }
 
-export function updateAlertReceiver(params) {
+export function updateAlertReceiver (params) {
   return request(`${baseUrl}/alert/receiver`, {
     method: `PUT`,
     body: {
       ...params
     }
-  });
+  })
 }
 
-export function addAlertReceiver(params) {
+export function addAlertReceiver (params) {
   return request(`${baseUrl}/alert/receiver`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
-export function deleteAlertReceivers(params) {
+export function deleteAlertReceivers (params) {
   return request(`${baseUrl}/alert/receiver/batch`, {
     method: `DELETE`,
     body: [...params.list]
-  });
+  })
 }
 
-export function fetchAlertReport(params) {
+export function fetchAlertReport (params) {
   return request(`${baseUrl}/alert/receiver/test`, {
     method: `POST`,
     body: {
       ...params
     }
-  });
+  })
 }
 
-export function bindingSelector(params) {
+export function bindingSelector (params) {
   return request(`${baseUrl}/proxy-selector/binding`,
     {
       method: `POST`,
       body: params
-    });
+    })
 }
 
-export function updateDiscoveryUpstream(discoveryHandlerId, upstreams) {
+export function updateDiscoveryUpstream (discoveryHandlerId, upstreams) {
   return request(`${baseUrl}/discovery-upstream/${discoveryHandlerId}`,
     {
-        method: `PUT`,
-        body: upstreams
-    });
+      method: `PUT`,
+      body: upstreams
+    })
 }
 
 
diff --git a/src/utils/download.js b/src/utils/download.js
new file mode 100644
index 00000000..b4990e09
--- /dev/null
+++ b/src/utils/download.js
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import fetch from 'dva/fetch'
+
+/**
+ * Requests a URL, for downloading.
+ *
+ * @param  {string} url       The URL we want to request
+ * @param  {object} [options] The options we want to pass to "fetch"
+ * @return {object}           An object containing either "data" or "err"
+ */
+export default async function download (url, options) {
+  const defaultOptions = {
+    method: 'GET',
+  }
+
+  const newOptions = { ...defaultOptions, ...options }
+
+  // add token
+  let token = window.sessionStorage.getItem("token")
+  if (token) {
+    if (!newOptions.headers) {
+      newOptions.headers = {}
+    }
+    newOptions.headers = { ...newOptions.headers, "X-Access-Token": token }
+  }
+  try {
+    const response = await fetch(url, newOptions)
+    const disposition = response.headers.get('Content-Disposition')
+    const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
+    const matches = filenameRegex.exec(disposition)
+    let filename = 'download'
+    if (matches != null && matches[1]) {
+      filename = matches[1].replace(/['"]/g, '')
+    }
+
+    const blob = await response.blob()
+
+    const a = document.createElement('a')
+    a.href = URL.createObjectURL(blob) // use blob obj to create URL
+    a.download = filename // use the file name from backend 
+    document.body.appendChild(a)
+    a.click()
+    document.body.removeChild(a)
+  } catch (error) {
+    throw new Error(`下载文件失败:${error}`)
+  }
+}

Reply via email to