Browse Source

登录成功

zhangjie 2 năm trước cách đây
mục cha
commit
0ae744f9dd

+ 1 - 1
dist_electron/package.json

@@ -17,7 +17,7 @@
   "dependencies": {
     "axios": "^0.19.2",
     "core-js": "^3.6.4",
-    "crypto": "^1.0.1",
+    "crypto-js": "^4.0.0",
     "deepmerge": "^4.2.2",
     "element-ui": "^2.14.1",
     "log4js": "^6.3.0",

BIN
extra/database/client.rdb


+ 1 - 1
package.json

@@ -17,7 +17,7 @@
   "dependencies": {
     "axios": "^0.19.2",
     "core-js": "^3.6.4",
-    "crypto": "^1.0.1",
+    "crypto-js": "^4.0.0",
     "deepmerge": "^4.2.2",
     "element-ui": "^2.14.1",
     "log4js": "^6.3.0",

+ 7 - 0
src/constants/app.js

@@ -0,0 +1,7 @@
+import { randomCode } from "../plugins/utils";
+
+export const APP_TITLE = "试卷电子化";
+
+export const PLATFORM = "WEB";
+
+export const DEVICE_ID = randomCode(32);

+ 2 - 89
src/main.js

@@ -1,115 +1,28 @@
 import Vue from "vue";
-import axios from "axios";
 
 import App from "./App.vue";
 import router from "./router";
 import store from "./store";
 import globalVuePlugins from "./plugins/globalVuePlugins";
-// 系统初始采集配置
-import CONFIG from "./config";
 
 // https://github.com/RobinCK/vue-ls
 import VueLocalStorage from "vue-ls";
-import ElementUI, { Message } from "element-ui";
+import ElementUI from "element-ui";
 import "element-ui/lib/theme-chalk/index.css";
 import "./assets/styles/index.scss";
 
 import { initConfigData } from "@/plugins/env";
-import log4js from "./plugins/logger";
-const logger = log4js.getLogger("request");
 
 Vue.use(ElementUI, { size: "small" });
 Vue.use(VueLocalStorage);
 Vue.use(globalVuePlugins);
 
 // 加载采集配置
-const GLOBAL = initConfigData(CONFIG);
+const GLOBAL = initConfigData({});
 Vue.prototype.GLOBAL = GLOBAL;
 
 Vue.config.productionTip = false;
 
-// logger
-const addLog = (datas, type) => {
-  if (type === "start") {
-    const msg = `${datas.url},开始请求`;
-    logger.info(msg);
-  } else if (type === "success") {
-    const msg = `${datas.config.url},请求成功`;
-    logger.info(msg);
-  } else {
-    const msg = `${datas.config.url},请求错误,错误信息:${datas.response.data.status} - ${datas.response.data.message}`;
-    logger.error(msg);
-  }
-};
-
-// axios interceptors
-var load = "";
-// 同一时间有多个请求时,会形成队列。在第一个请求创建loading,在最后一个响应关闭loading
-var queue = [];
-axios.interceptors.request.use(
-  config => {
-    // 显示loading提示
-    if (!queue.length && !config["showTinyTips"] && !config["silentRequest"]) {
-      load = Message({
-        customClass: "el-message-loading",
-        iconClass: "el-message__icon el-icon-loading",
-        message: "加载中...",
-        duration: 0
-      });
-    }
-
-    queue.push(1);
-
-    // 为请求地址添加全局domain
-    if (config.url.indexOf("http://") < 0) {
-      let domain = Vue.ls.get("domain", "");
-      config.url = domain + config.url;
-    }
-
-    // 为请求头添加信息
-    let user = Vue.ls.get("user", { userId: "" });
-    config.headers["userId"] = user.userId;
-
-    // 设置延迟时效
-    config.timeout = 10 * 60 * 1000;
-
-    addLog(config, "start");
-    return config;
-  },
-  error => {
-    // console.log(error);
-    // logger.error("");
-    // 关闭loading提示
-    // 串联并发请求,延时处理是为防止多个loading实例闪屏。
-    setTimeout(() => {
-      queue.shift();
-      if (!queue.length) load && load();
-    }, 100);
-    return Promise.reject(error);
-  }
-);
-axios.interceptors.response.use(
-  response => {
-    addLog(response, "success");
-    // 关闭loading提示
-    setTimeout(() => {
-      queue.shift();
-      if (!queue.length) load && load();
-    }, 100);
-    return response;
-  },
-  error => {
-    addLog(error, "error");
-
-    // 关闭loading提示
-    setTimeout(() => {
-      queue.shift();
-      if (!queue.length) load && load();
-    }, 100);
-    return Promise.reject(error);
-  }
-);
-
 new Vue({
   router,
   store,

+ 10 - 1
src/mixins/initStoreMixin.js

@@ -27,7 +27,12 @@ export default {
     },
     async initStore() {
       const storeDict = await db.getAllDict();
-      const needInitDict = ["startCountTime", "lastLoginUser", "domain"];
+      const needInitDict = [
+        "startCountTime",
+        "lastLoginUser",
+        "domain",
+        "schoolCode"
+      ];
       for (let i = 0; i < needInitDict.length; i++) {
         if (!Object.prototype.hasOwnProperty.call(storeDict, needInitDict[i])) {
           await db.initDict(needInitDict[i]);
@@ -37,6 +42,10 @@ export default {
       const domain = storeDict["domain"] || "";
       this.$store.commit("setDomain", domain);
       this.$ls.set("domain", domain);
+
+      const schoolCode = storeDict["schoolCode"] || "";
+      this.$store.commit("setSchoolCode", schoolCode);
+      this.$ls.set("schoolCode", schoolCode);
     }
   }
 };

+ 8 - 5
src/modules/client/api.js

@@ -1,12 +1,15 @@
-import { $post, $get } from "@/plugins/axios";
+import { $post, $postParam } from "@/plugins/axios";
 
 export const uploadFormalImage = (datas, config = {}) => {
-  return $post(`/api/file/`, datas, { ...config, showTinyTips: true });
+  return $post(`/api/admin/client/picture/upload`, datas, {
+    ...config,
+    slientRequest: true
+  });
 };
 
-export const getLevelList = examId => {
-  return $get(`/api/level/${examId}`);
+export const bingScanUser = ({ paperScanTaskId, userId }) => {
+  return $postParam(`/api/admin/client/bind/user`, { paperScanTaskId, userId });
 };
 export const taskListPage = datas => {
-  return $get(`/api/level/`, datas);
+  return $postParam(`/api/admin/client/task/page`, datas);
 };

+ 6 - 0
src/modules/client/components/ScanTaskDialog.vue

@@ -55,6 +55,7 @@
 </template>
 
 <script>
+import { bingScanUser } from "../api";
 import {
   getPreUploadFilesAutoSerial,
   getPreUploadFileCount,
@@ -129,6 +130,11 @@ export default {
       if (this.loading) return;
       this.loading = true;
 
+      await bingScanUser({
+        paperScanTaskId: this.task.id,
+        userId: this.user.id
+      });
+
       this.scaningImageList = [];
       this.scanStatus = "START";
       this.getInitFile();

+ 1 - 0
src/modules/client/components/ScanTaskProcessDialog.vue

@@ -33,6 +33,7 @@
         <span class="color-danger">
           {{ realScanCount }}
         </span>
+        <i v-if="scanStatus === 'START'" class="el-icon-loading"></i>
       </el-form-item>
     </el-form>
     <div slot="footer">

+ 5 - 1
src/modules/client/views/TaskManage.vue

@@ -45,7 +45,7 @@
           </el-select>
         </el-form-item>
         <el-form-item label-width="0px">
-          <el-button type="primary" @click="toPage(1)">查询</el-button>
+          <el-button type="primary" @click="search">查询</el-button>
         </el-form-item>
       </el-form>
     </div>
@@ -174,6 +174,10 @@ export default {
     };
   },
   methods: {
+    search() {
+      this.cacheData[this.curTab] = {};
+      this.toPage(1);
+    },
     async getList() {
       const datas = {
         ...this.filter,

+ 1 - 1
src/modules/login/api.js

@@ -1,5 +1,5 @@
 import { $post } from "@/plugins/axios";
 
 export const login = datas => {
-  return $post("/api/admin/common/login", datas);
+  return $post("/api/admin/client/user/login", datas);
 };

+ 8 - 2
src/modules/login/router.js

@@ -10,12 +10,18 @@ export default {
     {
       path: "/login",
       name: "Login",
-      component: Login
+      component: Login,
+      meta: {
+        noRequire: true
+      }
     },
     {
       path: "/setting",
       name: "Setting",
-      component: Setting
+      component: Setting,
+      meta: {
+        noRequire: true
+      }
     }
   ]
 };

+ 18 - 14
src/modules/login/views/Login.vue

@@ -32,6 +32,7 @@
               <i class="icon icon-password" slot="prefix"></i>
             </el-input>
           </el-form-item>
+          <el-form-item prop="schoolCode"></el-form-item>
           <el-form-item>
             <el-button
               type="primary"
@@ -40,12 +41,6 @@
               @click="submit"
               >登录</el-button
             >
-            <el-button
-              type="primary"
-              size="large"
-              @click="$router.push({ name: 'Home' })"
-              >任务管理</el-button
-            >
           </el-form-item>
         </el-form>
       </div>
@@ -58,6 +53,7 @@ import { password } from "@/plugins/formRules";
 import initStoreMixin from "../../../mixins/initStoreMixin";
 import { formatDate } from "../../../plugins/utils";
 import { login } from "../api";
+import { Base64 } from "@/plugins/crypto";
 
 export default {
   name: "login",
@@ -65,6 +61,8 @@ export default {
   data() {
     return {
       loginModel: {
+        schoolCode: "",
+        type: "ACCOUNT",
         loginname: "",
         password: ""
       },
@@ -77,7 +75,14 @@ export default {
             trigger: "change"
           }
         ],
-        password
+        password,
+        schoolCode: [
+          {
+            required: true,
+            message: "学校编码缺失",
+            trigger: "change"
+          }
+        ]
       },
       isSubmit: false
     };
@@ -89,11 +94,7 @@ export default {
   methods: {
     async initData() {
       await this.initStore();
-      const lastLoginUser = await this.getLastLoginUser();
-
-      if (lastLoginUser) {
-        this.loginModel = { ...JSON.parse(lastLoginUser) };
-      }
+      this.loginModel.schoolCode = this.$ls.get("schoolCode");
     },
     toSet() {
       this.$router.push({ name: "Setting" });
@@ -110,14 +111,17 @@ export default {
 
       if (this.isSubmit) return;
       this.isSubmit = true;
-      const data = await login(this.loginModel).catch(() => {});
+      let datas = {
+        ...this.loginModel
+      };
+      datas.password = Base64(datas.password);
+      const data = await login(datas).catch(() => {});
       this.isSubmit = false;
       if (!data) return;
 
       data.loginTime = formatDate();
       data.name = this.loginModel.loginName;
 
-      await this.setLastLoginUser(this.loginModel);
       this.$ls.set("user", data);
       this.$store.commit("setUser", data);
       if (data.orgInfo) this.$ls.set("orgId", data.orgInfo.id);

+ 35 - 14
src/modules/login/views/Setting.vue

@@ -1,8 +1,9 @@
 <template>
   <div class="setting login-body">
     <div class="login-form">
-      <h2 class="login-form-title">服务器IP地址设置</h2>
+      <h2 class="login-form-title">设置</h2>
       <el-form ref="setForm" :model="setModel" :rules="setRules" inline>
+        <h3 class="mb-1">服务器IP地址:</h3>
         <el-form-item prop="ipCont1">
           <el-input-number
             style="width:60px;"
@@ -62,6 +63,12 @@
             :controls="false"
           ></el-input-number>
         </el-form-item>
+        <br />
+        <h3 class="mb-1">学校编号:</h3>
+        <el-form-item prop="schoolCode">
+          <el-input v-model="setModel.schoolCode" clearable></el-input>
+        </el-form-item>
+
         <br />
         <el-form-item>
           <el-button
@@ -69,7 +76,7 @@
             :disabled="loading"
             size="large"
             @click="submit"
-            >登录</el-button
+            >确定</el-button
           >
         </el-form-item>
       </el-form>
@@ -83,7 +90,7 @@ import db from "@/plugins/db";
 export default {
   name: "setting",
   data() {
-    const ipValidator = [
+    const contValidator = [
       {
         required: true,
         message: " ",
@@ -96,14 +103,16 @@ export default {
         ipCont2: undefined,
         ipCont3: undefined,
         ipCont4: undefined,
-        port: undefined
+        port: undefined,
+        schoolCode: ""
       },
       setRules: {
-        ipCont1: [...ipValidator],
-        ipCont2: [...ipValidator],
-        ipCont3: [...ipValidator],
-        ipCont4: [...ipValidator],
-        port: [...ipValidator]
+        ipCont1: [...contValidator],
+        ipCont2: [...contValidator],
+        ipCont3: [...contValidator],
+        ipCont4: [...contValidator],
+        port: [...contValidator],
+        schoolCode: [...contValidator]
       },
       loading: false
     };
@@ -114,6 +123,9 @@ export default {
     },
     domain() {
       return this.$store.state.domain;
+    },
+    schoolCode() {
+      return this.$store.state.schoolCode;
     }
   },
   mounted() {
@@ -127,20 +139,23 @@ export default {
           ipCont2: undefined,
           ipCont3: undefined,
           ipCont4: undefined,
-          port: undefined
+          port: undefined,
+          schoolCode: this.schoolCode
         };
         return;
       }
 
       const [ipCont1, ipCont2, ipCont3, ipCont4, port] = this.domain
         .replace("http://", "")
-        .split(/(\.|:)/);
+        .split(/\.|:/);
+
       this.setModel = {
         ipCont1: Number(ipCont1),
         ipCont2: Number(ipCont2),
         ipCont3: Number(ipCont3),
         ipCont4: Number(ipCont4),
-        port: Number(port)
+        port: Number(port),
+        schoolCode: this.schoolCode
       };
     },
     async submit() {
@@ -154,10 +169,16 @@ export default {
       }
 
       this.$store.commit("setDomain", this.domainEdited);
-      const res = await db.setDict("domain", this.domainEdited).catch(() => {});
-      if (res) {
+      let res1 = await db.setDict("domain", this.domainEdited).catch(() => {});
+      let res2 = await db
+        .setDict("schoolCode", this.setModel.schoolCode)
+        .catch(() => {});
+
+      if (res1 && res2) {
         this.$ls.set("domain", this.domainEdited);
         this.$store.commit("setDomain", this.domainEdited);
+        this.$ls.set("schoolCode", this.setModel.schoolCode);
+        this.$store.commit("setSchoolCode", this.setModel.schoolCode);
         this.$message.success("设置成功!");
         this.$router.go(-1);
       } else {

+ 235 - 94
src/plugins/axios.js

@@ -1,78 +1,211 @@
 import axios from "axios";
-import qs from "qs";
-import { Message, Notification } from "element-ui";
+import { Message, MessageBox, Notification } from "element-ui";
 import { objTypeOf } from "./utils";
-// import router from "../router";
-// import Vue from "vue";
-let tinyTipsIsShow = false;
+import router from "../router";
+import Vue from "vue";
+
+import { getAuthorization } from "./crypto";
+import { PLATFORM, DEVICE_ID } from "../constants/app";
+import { initSyncTime, fetchTime } from "./syncServerTime";
+
+import log4js from "./logger";
+const logger = log4js.getLogger("request");
+
+// logger
+const addLog = (datas, type) => {
+  if (type === "start") {
+    const msg = `${datas.url},开始请求`;
+    logger.info(msg);
+  } else if (type === "success") {
+    const msg = `${datas.config.url},请求成功`;
+    logger.info(msg);
+  } else {
+    const msg = `${datas.config.url},请求错误,错误信息:${datas.response.data.status} - ${datas.response.data.message}`;
+    logger.error(msg);
+  }
+};
+
+// axios interceptors
+var load = "";
+// 同一时间有多个请求时,会形成队列。在第一个请求创建loading,在最后一个响应关闭loading
+var queue = [];
+axios.interceptors.request.use(
+  config => {
+    // 显示loading提示
+    if (!queue.length && !config["silentRequest"]) {
+      load = Message({
+        customClass: "el-message-loading",
+        iconClass: "el-message__icon el-icon-loading",
+        message: "加载中...",
+        duration: 0
+      });
+    }
+
+    queue.push(1);
+
+    // 为请求地址添加全局domain
+    let domain = Vue.ls.get("domain", "");
+    if (config.url.indexOf("http://") < 0) {
+      config.url = domain + config.url;
+    }
+
+    // 为请求头添加鉴权信息
+    let token = Vue.ls.get("token");
+    if (token) {
+      const ids = {
+        orgId: Vue.ls.get("orgId", ""),
+        schoolId: Vue.ls.get("schoolId", ""),
+        userId: Vue.ls.get("user", { id: "" }).id
+      };
+      Object.entries(ids).forEach(([key, val]) => {
+        if (val === null || val === "null" || val === "") return;
+        config.headers[key] = val;
+      });
+
+      // 新版鉴权
+      const sessionId = Vue.ls.get("user", { sessionId: "" }).sessionId;
+      const timestamp = fetchTime();
+      const Authorization = getAuthorization(
+        {
+          token: token,
+          timestamp,
+          account: sessionId,
+          uri: config.url.split("?")[0],
+          method: config.method
+        },
+        "token"
+      );
+      config.headers["Authorization"] = Authorization;
+      config.headers["time"] = timestamp;
+    }
+    config.headers["deviceId"] = DEVICE_ID;
+    config.headers["platform"] = PLATFORM;
+    config.headers["domain"] = domain;
+
+    // 设置延迟时效
+    config.timeout = 10 * 60 * 1000;
+
+    addLog(config, "start");
+    return config;
+  },
+  error => {
+    // console.log(error);
+    // logger.error("");
+    // 关闭loading提示
+    // 串联并发请求,延时处理是为防止多个loading实例闪屏。
+    setTimeout(() => {
+      queue.shift();
+      if (!queue.length) load && load.close();
+    }, 100);
+    return Promise.reject(error);
+  }
+);
+axios.interceptors.response.use(
+  response => {
+    initSyncTime(new Date(response.headers.date).getTime());
+    addLog(response, "success");
+    // 关闭loading提示
+    setTimeout(() => {
+      queue.shift();
+      if (!queue.length) load && load.close();
+    }, 100);
+    return response;
+  },
+  error => {
+    if (error.response) {
+      initSyncTime(new Date(error.response.headers.date).getTime());
+    }
+    addLog(error, "error");
+
+    // 关闭loading提示
+    setTimeout(() => {
+      queue.shift();
+      if (!queue.length) load && load.close();
+    }, 100);
+    return Promise.reject(error);
+  }
+);
+
+const mdData = datas => {
+  let nData = {};
+  if (!datas) return nData;
+  Object.entries(datas).forEach(([key, val]) => {
+    if (val === null || val === "null" || val === "") return;
+    nData[key] = val;
+  });
+  return nData;
+};
 
 /**
  * errorCallback 请求失败的回调
  * @param {Object} error 请求失败时的错误信息
  */
 const errorCallback = (error, config = {}) => {
-  const showTinyTips = config && config["showTinyTips"];
   const slientRequest = config && config["silentRequest"];
-
-  let content = "";
-  if (error.response) {
-    content =
-      (error.response.data && error.response.data.message) || "服务错误";
-  } else if (error.request) {
-    content = "请求错误";
-    if (error.message.indexOf("timeout") > -1) {
-      content = "请求超时";
-    }
-  } else {
+  if (slientRequest) {
     return error;
   }
 
-  if (slientRequest) {
-    return error;
+  if (error.response) {
+    return errorDataCallback(error.response);
   }
 
-  if (showTinyTips) {
-    if (!tinyTipsIsShow) {
-      Message.error({
-        content: "上传异常",
-        duration: 5,
-        onClose() {
-          tinyTipsIsShow = false;
-        }
-      });
-      tinyTipsIsShow = true;
+  if (error.request) {
+    let message = "请求错误";
+    if (error.message.indexOf("timeout") > -1) {
+      message = "请求超时";
     }
-  } else {
-    content = content.indexOf("###") !== -1 ? "参数错误" : content;
-    Notification.error({ title: "错误提示", message: content });
+    Notification.error({ title: "错误提示", message });
+    return error;
   }
+
+  Notification.error({ title: "错误提示", message: "请求错误" });
   return error;
 };
 
+let unauthMsgBoxIsShow = false;
 /**
  * errorDataCallback 请求成功,结果有误的回调
- * @param {Object} error Response中的data信息
+ * @param {Object} response Response信息
  */
-// const errorDataCallback = error => {
-//   let content = error.message || "数据错误";
-//   content = content.indexOf("###") !== -1 ? "参数错误" : content;
-
-//   // TODO:自定义处理逻辑,以下为epcc实例
-//   if (error.code === -100) {
-//     content = "身份验证失效,请重新登录";
-//     ViewUI.Modal.confirm({
-//       title: "重新登陆?",
-//       content,
-//       onOk: () => {
-//         Vue.ls.clear();
-//         router.push({ name: "Login" });
-//       }
-//     });
-//   } else {
-//     ViewUI.Notice.error({ title: "错误提示", desc: content });
-//   }
-//   return error;
-// };
+const errorDataCallback = response => {
+  if (objTypeOf(response.data) === "blob") return response.data;
+
+  const error = response.data;
+  let message = error.message || error.error || "请求错误";
+  const unauthStatus = [401, 403];
+
+  if (unauthStatus.includes(response.status)) {
+    if (error.code === 401001 && message === "没有权限") {
+      Notification.error({ title: "错误提示", message });
+      return error;
+    }
+
+    if (unauthMsgBoxIsShow) return error;
+
+    const exposeMsgs = ["系统授权信息已过期,请联系系统管理员激活!"];
+    unauthMsgBoxIsShow = true;
+    message = exposeMsgs.includes(message)
+      ? message
+      : "身份验证失效,请重新登录";
+    MessageBox.confirm(message, "重新登陆?", {
+      type: "warning",
+      closeOnClickModal: false,
+      closeOnPressEscape: false,
+      showClose: false,
+      callback: action => {
+        unauthMsgBoxIsShow = false;
+        if (action !== "confirm") return;
+        Vue.ls.clear();
+        router.push({ name: "Login" });
+      }
+    });
+  } else {
+    Notification.error({ title: "错误提示", message });
+  }
+
+  return error;
+};
 
 /**
  * response format
@@ -87,12 +220,22 @@ const errorCallback = (error, config = {}) => {
  * @param {Object} data Response中的data信息
  */
 const successCallback = data => {
-  return data;
-  // if (data.code === 0) {
-  //   return data.data;
-  // } else {
-  //   throw new Error(errorDataCallback(data));
-  // }
+  if (data.code === 200) {
+    if (
+      objTypeOf(data.data) === "object" &&
+      Object.prototype.hasOwnProperty.call(data.data, "success")
+    ) {
+      if (data.data.success) {
+        return data.data;
+      } else {
+        return Promise.reject(data.data);
+      }
+    } else {
+      return data.data;
+    }
+  } else {
+    return Promise.reject(data.data);
+  }
 };
 
 /**
@@ -101,20 +244,31 @@ const successCallback = data => {
  * @param {Object} datas 请求数据
  */
 const $get = (url, datas) => {
-  let sqDatas = "";
-  if (datas) {
-    sqDatas = qs.stringify(datas, {
-      arrayFormat: "brackets"
+  return axios
+    .get(url, { params: mdData(datas) })
+    .then(rep => {
+      return successCallback(rep.data);
+    })
+    .catch(error => {
+      return Promise.reject(errorCallback(error));
     });
-    url += "?" + sqDatas;
-  }
+};
+
+/**
+ * get请求
+ * @param {String} url 请求地址
+ * @param {Object} datas 请求数据
+ */
+const $postParam = (url, datas, config = {}) => {
   return axios
-    .get(url)
+    .post(url, {}, { ...config, params: mdData(datas) })
     .then(rep => {
+      if (config["responseType"] === "blob") return rep;
+
       return successCallback(rep.data);
     })
     .catch(error => {
-      throw new Error(errorCallback(error));
+      return Promise.reject(errorCallback(error, config));
     });
 };
 
@@ -124,19 +278,22 @@ const $get = (url, datas) => {
  * @param {Object} datas 请求数据
  */
 const $post = (url, datas, config = {}) => {
-  let sqDatas = "";
-  if (objTypeOf(datas) === "object" || objTypeOf(datas) === "array") {
-    sqDatas = qs.stringify(datas, { allowDots: true });
+  let sqDatas = {};
+  if (datas.constructor === Object) {
+    sqDatas = mdData(datas);
   } else {
     sqDatas = datas;
   }
+
   return axios
     .post(url, sqDatas, config)
     .then(rep => {
+      if (config["responseType"] === "blob") return rep;
+
       return successCallback(rep.data);
     })
     .catch(error => {
-      throw new Error(errorCallback(error, config));
+      return Promise.reject(errorCallback(error, config));
     });
 };
 
@@ -146,18 +303,13 @@ const $post = (url, datas, config = {}) => {
  * @param {Object} datas
  */
 const $del = (url, datas) => {
-  let sqDatas = "";
-  if (datas) {
-    sqDatas = qs.stringify(datas, { arrayFormat: "brackets" });
-    url += "?" + sqDatas;
-  }
   return axios
-    .delete(url)
+    .delete(url, { params: mdData(datas) })
     .then(rep => {
       return rep.data;
     })
     .catch(error => {
-      throw new Error(errorCallback(error));
+      return Promise.reject(errorCallback(error));
     });
 };
 
@@ -168,12 +320,12 @@ const $del = (url, datas) => {
  */
 const $put = (url, datas) => {
   return axios
-    .put(url, datas)
+    .put(url, { params: mdData(datas) })
     .then(rep => {
       return rep.data;
     })
     .catch(error => {
-      throw new Error(errorCallback(error));
+      return Promise.reject(errorCallback(error));
     });
 };
 
@@ -184,24 +336,13 @@ const $put = (url, datas) => {
  */
 const $patch = (url, datas) => {
   return axios
-    .patch(url, datas)
+    .patch(url, { params: mdData(datas) })
     .then(rep => {
       return rep.data;
     })
     .catch(error => {
-      throw new Error(errorCallback(error));
+      return Promise.reject(errorCallback(error));
     });
 };
 
-const $directGet = (url, datas) => {
-  let sqDatas = "";
-  if (datas) {
-    sqDatas = qs.stringify(datas, {
-      arrayFormat: "brackets"
-    });
-    url += "?" + sqDatas;
-  }
-  return axios.get(url, { silentRequest: true });
-};
-
-export { $get, $post, $del, $put, $patch, $directGet };
+export { $get, $postParam, $post, $del, $put, $patch };

+ 42 - 0
src/plugins/crypto.js

@@ -0,0 +1,42 @@
+const CryptoJS = require("crypto-js");
+
+export const Base64 = content => {
+  const words = CryptoJS.enc.Utf8.parse(content);
+  const base64Str = CryptoJS.enc.Base64.stringify(words);
+
+  return base64Str;
+};
+
+export const AES = content => {
+  const KEY = "1234567890123456";
+  const IV = "1234567890123456";
+
+  var key = CryptoJS.enc.Utf8.parse(KEY);
+  var iv = CryptoJS.enc.Utf8.parse(IV);
+  var encrypted = CryptoJS.AES.encrypt(content, key, { iv: iv });
+  return encrypted.toString();
+};
+
+/**
+ * 获取authorisation
+ * @param {Object} infos 相关信息
+ * @param {String} type 类别:secret、token两种
+ */
+export const getAuthorization = (infos, type) => {
+  // {type} {invoker}:base64(sha1(method&uri&timestamp&{secret}))
+  if (type === "secret") {
+    // accessKey | method&uri&timestamp&accessSecret
+    const str = `${infos.method.toLowerCase()}&${infos.uri}&${
+      infos.timestamp
+    }&${infos.accessSecret}`;
+    const sign = CryptoJS.enc.Base64.stringify(CryptoJS.SHA1(str));
+    return `Secret ${infos.accessKey}:${sign}`;
+  } else if (type === "token") {
+    // userId | method&uri&timestamp&token
+    const str = `${infos.method.toLowerCase()}&${infos.uri}&${
+      infos.timestamp
+    }&${infos.token}`;
+    const sign = CryptoJS.enc.Base64.stringify(CryptoJS.SHA1(str));
+    return `Token ${infos.account}:${sign}`;
+  }
+};

+ 2 - 0
src/plugins/imageUpload.js

@@ -2,6 +2,7 @@ const fs = require("fs");
 const path = require("path");
 const crypto = require("crypto");
 import { uploadFormalImage } from "../modules/client/api";
+import { Message } from "element-ui";
 
 /**
  * 文件上传
@@ -102,6 +103,7 @@ class UploadTask {
 
     let uploadResult = true;
     await toUploadImg(curTask).catch(() => {
+      Message.error("上传异常");
       uploadResult = false;
     });
     if (uploadResult) {

+ 28 - 0
src/plugins/syncServerTime.js

@@ -0,0 +1,28 @@
+let initLocalTime = null;
+let initServerTime = null;
+
+function getStorgeTime() {
+  const st = localStorage.getItem("st");
+  const unvalidVals = ["Infinity", "NaN", "null", "undefined"];
+  if (unvalidVals.includes(st + "")) {
+    return [Date.now(), Date.now()];
+  } else {
+    const [s, t] = st.split("_");
+    return [s * 1, t * 1];
+  }
+}
+
+const [serverTime, localTime] = getStorgeTime();
+initSyncTime(serverTime, localTime);
+
+function initSyncTime(serverTime, localTime = Date.now()) {
+  initLocalTime = localTime;
+  initServerTime = serverTime;
+  localStorage.setItem("st", `${initServerTime}_${initLocalTime}`);
+}
+
+function fetchTime() {
+  return Date.now() + initServerTime - initLocalTime;
+}
+
+export { initSyncTime, fetchTime };

+ 21 - 1
src/router.js

@@ -14,7 +14,7 @@ Vue.use(Router);
  * 3、不同模块打包不同文件。(webpackChunkName)
  */
 
-export default new Router({
+let router = new Router({
   routes: [
     {
       path: "/",
@@ -40,3 +40,23 @@ export default new Router({
     // }
   ]
 });
+
+// route interceptor
+router.beforeEach((to, from, next) => {
+  const token = Vue.ls.get("token");
+  if (to.meta.noRequire) {
+    next();
+    return;
+  }
+
+  if (!token) {
+    // 登录失效的处理
+    Vue.ls.clear();
+    next({ name: "Login" });
+    return;
+  }
+
+  next();
+});
+
+export default router;

+ 3 - 0
src/store.js

@@ -17,6 +17,9 @@ export default new Vuex.Store({
     },
     setDomain(state, domain) {
       state.domain = domain;
+    },
+    setSchoolCode(state, schoolCode) {
+      state.schoolCode = schoolCode;
     }
   },
   actions: {},

+ 97 - 99
yarn.lock

@@ -31,10 +31,10 @@
   dependencies:
     "@babel/highlight" "^7.18.6"
 
-"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8", "@babel/compat-data@^7.19.3":
-  version "7.19.3"
-  resolved "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.19.3.tgz#707b939793f867f5a73b2666e6d9a3396eb03151"
-  integrity sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==
+"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.19.3", "@babel/compat-data@^7.19.4":
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.19.4.tgz#95c86de137bf0317f3a570e1b6e996b427299747"
+  integrity sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==
 
 "@babel/core@^7.11.0", "@babel/core@^7.9.0":
   version "7.19.3"
@@ -57,12 +57,12 @@
     json5 "^2.2.1"
     semver "^6.3.0"
 
-"@babel/generator@^7.19.3":
-  version "7.19.3"
-  resolved "https://registry.npmmirror.com/@babel/generator/-/generator-7.19.3.tgz#d7f4d1300485b4547cb6f94b27d10d237b42bf59"
-  integrity sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==
+"@babel/generator@^7.19.3", "@babel/generator@^7.19.4":
+  version "7.19.5"
+  resolved "https://registry.npmmirror.com/@babel/generator/-/generator-7.19.5.tgz#da3f4b301c8086717eee9cab14da91b1fa5dcca7"
+  integrity sha512-DxbNz9Lz4aMZ99qPpO1raTbcrI1ZeYh+9NR9qhfkQIbFtVEqotHojEBxHzmxhVONkGt6VyrqVQcgpefMy9pqcg==
   dependencies:
-    "@babel/types" "^7.19.3"
+    "@babel/types" "^7.19.4"
     "@jridgewell/gen-mapping" "^0.3.2"
     jsesc "^2.5.1"
 
@@ -213,11 +213,11 @@
     "@babel/types" "^7.19.0"
 
 "@babel/helper-simple-access@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.npmmirror.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea"
-  integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz#be553f4951ac6352df2567f7daa19a0ee15668e7"
+  integrity sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==
   dependencies:
-    "@babel/types" "^7.18.6"
+    "@babel/types" "^7.19.4"
 
 "@babel/helper-skip-transparent-expression-wrappers@^7.18.9":
   version "7.18.9"
@@ -233,10 +233,10 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
-"@babel/helper-string-parser@^7.18.10":
-  version "7.18.10"
-  resolved "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56"
-  integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==
+"@babel/helper-string-parser@^7.19.4":
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
+  integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
 
 "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
   version "7.19.1"
@@ -259,13 +259,13 @@
     "@babel/types" "^7.19.0"
 
 "@babel/helpers@^7.19.0":
-  version "7.19.0"
-  resolved "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.19.0.tgz#f30534657faf246ae96551d88dd31e9d1fa1fc18"
-  integrity sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.19.4.tgz#42154945f87b8148df7203a25c31ba9a73be46c5"
+  integrity sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==
   dependencies:
     "@babel/template" "^7.18.10"
-    "@babel/traverse" "^7.19.0"
-    "@babel/types" "^7.19.0"
+    "@babel/traverse" "^7.19.4"
+    "@babel/types" "^7.19.4"
 
 "@babel/highlight@^7.18.6":
   version "7.18.6"
@@ -276,10 +276,10 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.18.10", "@babel/parser@^7.18.4", "@babel/parser@^7.19.3", "@babel/parser@^7.7.0":
-  version "7.19.3"
-  resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.19.3.tgz#8dd36d17c53ff347f9e55c328710321b49479a9a"
-  integrity sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==
+"@babel/parser@^7.18.10", "@babel/parser@^7.18.4", "@babel/parser@^7.19.3", "@babel/parser@^7.19.4", "@babel/parser@^7.7.0":
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.19.4.tgz#03c4339d2b8971eb3beca5252bafd9b9f79db3dc"
+  integrity sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==
 
 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
   version "7.18.6"
@@ -383,14 +383,14 @@
     "@babel/helper-plugin-utils" "^7.18.6"
     "@babel/plugin-syntax-numeric-separator" "^7.10.4"
 
-"@babel/plugin-proposal-object-rest-spread@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.npmmirror.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz#f9434f6beb2c8cae9dfcf97d2a5941bbbf9ad4e7"
-  integrity sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==
+"@babel/plugin-proposal-object-rest-spread@^7.19.4":
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz#a8fc86e8180ff57290c91a75d83fe658189b642d"
+  integrity sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==
   dependencies:
-    "@babel/compat-data" "^7.18.8"
-    "@babel/helper-compilation-targets" "^7.18.9"
-    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/compat-data" "^7.19.4"
+    "@babel/helper-compilation-targets" "^7.19.3"
+    "@babel/helper-plugin-utils" "^7.19.0"
     "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
     "@babel/plugin-transform-parameters" "^7.18.8"
 
@@ -579,12 +579,12 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-block-scoping@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.npmmirror.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz#f9b7e018ac3f373c81452d6ada8bd5a18928926d"
-  integrity sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==
+"@babel/plugin-transform-block-scoping@^7.19.4":
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz#315d70f68ce64426db379a3d830e7ac30be02e9b"
+  integrity sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-plugin-utils" "^7.19.0"
 
 "@babel/plugin-transform-classes@^7.19.0":
   version "7.19.0"
@@ -608,12 +608,12 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.18.9"
 
-"@babel/plugin-transform-destructuring@^7.18.13":
-  version "7.18.13"
-  resolved "https://registry.npmmirror.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz#9e03bc4a94475d62b7f4114938e6c5c33372cbf5"
-  integrity sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow==
+"@babel/plugin-transform-destructuring@^7.19.4":
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz#46890722687b9b89e1369ad0bd8dc6c5a3b4319d"
+  integrity sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-plugin-utils" "^7.19.0"
 
 "@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4":
   version "7.18.6"
@@ -822,11 +822,11 @@
     "@babel/helper-plugin-utils" "^7.18.6"
 
 "@babel/preset-env@^7.11.0":
-  version "7.19.3"
-  resolved "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.19.3.tgz#52cd19abaecb3f176a4ff9cc5e15b7bf06bec754"
-  integrity sha512-ziye1OTc9dGFOAXSWKUqQblYHNlBOaDl8wzqf2iKXJAltYiR3hKHUKmkt+S9PppW7RQpq4fFCrwwpIDj/f5P4w==
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.19.4.tgz#4c91ce2e1f994f717efb4237891c3ad2d808c94b"
+  integrity sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==
   dependencies:
-    "@babel/compat-data" "^7.19.3"
+    "@babel/compat-data" "^7.19.4"
     "@babel/helper-compilation-targets" "^7.19.3"
     "@babel/helper-plugin-utils" "^7.19.0"
     "@babel/helper-validator-option" "^7.18.6"
@@ -841,7 +841,7 @@
     "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9"
     "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6"
     "@babel/plugin-proposal-numeric-separator" "^7.18.6"
-    "@babel/plugin-proposal-object-rest-spread" "^7.18.9"
+    "@babel/plugin-proposal-object-rest-spread" "^7.19.4"
     "@babel/plugin-proposal-optional-catch-binding" "^7.18.6"
     "@babel/plugin-proposal-optional-chaining" "^7.18.9"
     "@babel/plugin-proposal-private-methods" "^7.18.6"
@@ -865,10 +865,10 @@
     "@babel/plugin-transform-arrow-functions" "^7.18.6"
     "@babel/plugin-transform-async-to-generator" "^7.18.6"
     "@babel/plugin-transform-block-scoped-functions" "^7.18.6"
-    "@babel/plugin-transform-block-scoping" "^7.18.9"
+    "@babel/plugin-transform-block-scoping" "^7.19.4"
     "@babel/plugin-transform-classes" "^7.19.0"
     "@babel/plugin-transform-computed-properties" "^7.18.9"
-    "@babel/plugin-transform-destructuring" "^7.18.13"
+    "@babel/plugin-transform-destructuring" "^7.19.4"
     "@babel/plugin-transform-dotall-regex" "^7.18.6"
     "@babel/plugin-transform-duplicate-keys" "^7.18.9"
     "@babel/plugin-transform-exponentiation-operator" "^7.18.6"
@@ -895,7 +895,7 @@
     "@babel/plugin-transform-unicode-escapes" "^7.18.10"
     "@babel/plugin-transform-unicode-regex" "^7.18.6"
     "@babel/preset-modules" "^0.1.5"
-    "@babel/types" "^7.19.3"
+    "@babel/types" "^7.19.4"
     babel-plugin-polyfill-corejs2 "^0.3.3"
     babel-plugin-polyfill-corejs3 "^0.6.0"
     babel-plugin-polyfill-regenerator "^0.4.1"
@@ -914,9 +914,9 @@
     esutils "^2.0.2"
 
 "@babel/runtime@^7.11.0", "@babel/runtime@^7.8.4":
-  version "7.19.0"
-  resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
-  integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78"
+  integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==
   dependencies:
     regenerator-runtime "^0.13.4"
 
@@ -929,28 +929,28 @@
     "@babel/parser" "^7.18.10"
     "@babel/types" "^7.18.10"
 
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.19.3", "@babel/traverse@^7.7.0":
-  version "7.19.3"
-  resolved "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.19.3.tgz#3a3c5348d4988ba60884e8494b0592b2f15a04b4"
-  integrity sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.19.3", "@babel/traverse@^7.19.4", "@babel/traverse@^7.7.0":
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.19.4.tgz#f117820e18b1e59448a6c1fa9d0ff08f7ac459a8"
+  integrity sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==
   dependencies:
     "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.19.3"
+    "@babel/generator" "^7.19.4"
     "@babel/helper-environment-visitor" "^7.18.9"
     "@babel/helper-function-name" "^7.19.0"
     "@babel/helper-hoist-variables" "^7.18.6"
     "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/parser" "^7.19.3"
-    "@babel/types" "^7.19.3"
+    "@babel/parser" "^7.19.4"
+    "@babel/types" "^7.19.4"
     debug "^4.1.0"
     globals "^11.1.0"
 
-"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.19.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
-  version "7.19.3"
-  resolved "https://registry.npmmirror.com/@babel/types/-/types-7.19.3.tgz#fc420e6bbe54880bce6779ffaf315f5e43ec9624"
-  integrity sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==
+"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.19.3", "@babel/types@^7.19.4", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
+  version "7.19.4"
+  resolved "https://registry.npmmirror.com/@babel/types/-/types-7.19.4.tgz#0dd5c91c573a202d600490a35b33246fed8a41c7"
+  integrity sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==
   dependencies:
-    "@babel/helper-string-parser" "^7.18.10"
+    "@babel/helper-string-parser" "^7.19.4"
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
@@ -1186,9 +1186,9 @@
   integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
 
 "@types/node@*":
-  version "18.8.3"
-  resolved "https://registry.npmmirror.com/@types/node/-/node-18.8.3.tgz#ce750ab4017effa51aed6a7230651778d54e327c"
-  integrity sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==
+  version "18.8.4"
+  resolved "https://registry.npmmirror.com/@types/node/-/node-18.8.4.tgz#54be907698f40de8a45770b48486aa3cbd3adff7"
+  integrity sha512-WdlVphvfR/GJCLEMbNA8lJ0lhFNBj4SW3O+O5/cEGw9oYrv0al9zTwuQsq+myDUXgNx2jgBynoVgZ2MMJ6pbow==
 
 "@types/node@^12.0.12":
   version "12.20.55"
@@ -1457,10 +1457,10 @@
     semver "^6.1.0"
     strip-ansi "^6.0.0"
 
-"@vue/compiler-sfc@2.7.10":
-  version "2.7.10"
-  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.10.tgz#3fe08e780053a3bbf41328c65ae5dfdee0385206"
-  integrity sha512-55Shns6WPxlYsz4WX7q9ZJBL77sKE1ZAYNYStLs6GbhIOMrNtjMvzcob6gu3cGlfpCR4bT7NXgyJ3tly2+Hx8Q==
+"@vue/compiler-sfc@2.7.11":
+  version "2.7.11"
+  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.11.tgz#3b8a60b4145f615a5da023492ee34cc3bb2b545b"
+  integrity sha512-Cf8zvrZWjROgd8yPL8Tc+O3q/Y8ZGM0Y+8blrAvj1RQsVouzUY0oHcx8BA7Hybhb90JRnzeApFrlQGZRUdYpRw==
   dependencies:
     "@babel/parser" "^7.18.4"
     postcss "^8.4.14"
@@ -3145,11 +3145,9 @@ content-type@~1.0.4:
   integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
 
 convert-source-map@^1.7.0:
-  version "1.8.0"
-  resolved "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
-  integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
-  dependencies:
-    safe-buffer "~5.1.1"
+  version "1.9.0"
+  resolved "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
+  integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
 
 cookie-signature@1.0.6:
   version "1.0.6"
@@ -3325,16 +3323,16 @@ crypto-browserify@^3.11.0:
     randombytes "^2.0.0"
     randomfill "^1.0.3"
 
+crypto-js@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf"
+  integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==
+
 crypto-random-string@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
   integrity sha512-GsVpkFPlycH7/fRR7Dhcmnoii54gV1nz7y4CWyeFS14N+JVBBhY+r8amRHE4BwSYal7BPTDp8isvAlCxyFt3Hg==
 
-crypto@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.npmmirror.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037"
-  integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==
-
 css-color-names@0.0.4, css-color-names@^0.0.4:
   version "0.0.4"
   resolved "https://registry.npmmirror.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@@ -3656,9 +3654,9 @@ default-gateway@^5.0.5:
     execa "^3.3.0"
 
 defaults@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.npmmirror.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
-  integrity sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==
+  version "1.0.4"
+  resolved "https://registry.npmmirror.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a"
+  integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==
   dependencies:
     clone "^1.0.2"
 
@@ -6937,9 +6935,9 @@ minimatch@~3.0.2:
     brace-expansion "^1.1.7"
 
 minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
-  version "1.2.6"
-  resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
-  integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
+  version "1.2.7"
+  resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
+  integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
 
 minimist@~0.0.1:
   version "0.0.10"
@@ -7093,9 +7091,9 @@ mz@^2.4.0:
     thenify-all "^1.0.0"
 
 nan@^2.12.1:
-  version "2.16.0"
-  resolved "https://registry.npmmirror.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916"
-  integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==
+  version "2.17.0"
+  resolved "https://registry.npmmirror.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
+  integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==
 
 nanoid@^3.3.4:
   version "3.3.4"
@@ -10538,9 +10536,9 @@ vue-style-loader@^4.1.0, vue-style-loader@^4.1.2:
     loader-utils "^1.0.2"
 
 vue-template-compiler@^2.6.11:
-  version "2.7.10"
-  resolved "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.10.tgz#9e20f35b2fdccacacf732dd7dedb49bf65f4556b"
-  integrity sha512-QO+8R9YRq1Gudm8ZMdo/lImZLJVUIAM8c07Vp84ojdDAf8HmPJc7XB556PcXV218k2AkKznsRz6xB5uOjAC4EQ==
+  version "2.7.11"
+  resolved "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.11.tgz#e18e8e0dcb2647e8d6ff2ede8a3a92e677ff8dea"
+  integrity sha512-17QnXkFiBLOH3gGCA3nWAWpmdlTjOWLyP/2eg5ptgY1OvDBuIDGOW9FZ7ZSKmF1UFyf56mLR3/E1SlCTml1LWQ==
   dependencies:
     de-indent "^1.0.2"
     he "^1.2.0"
@@ -10551,11 +10549,11 @@ vue-template-es2015-compiler@^1.9.0:
   integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
 
 vue@^2.6.11:
-  version "2.7.10"
-  resolved "https://registry.npmmirror.com/vue/-/vue-2.7.10.tgz#ae516cc6c88e1c424754468844218fdd5e280f40"
-  integrity sha512-HmFC70qarSHPXcKtW8U8fgIkF6JGvjEmDiVInTkKZP0gIlEPhlVlcJJLkdGIDiNkIeA2zJPQTWJUI4iWe+AVfg==
+  version "2.7.11"
+  resolved "https://registry.npmmirror.com/vue/-/vue-2.7.11.tgz#e051d54a131e7094c3ea3a86b2c6ecf25f8d0002"
+  integrity sha512-VPAW5QelT7Tx6UoSw/cwx/jDROOKAK1y/Q0o7HkmVJ1WAypE7w1+UoFa+KsGxy1aYdHPU1oODB3vR6XwSfVhDg==
   dependencies:
-    "@vue/compiler-sfc" "2.7.10"
+    "@vue/compiler-sfc" "2.7.11"
     csstype "^3.1.0"
 
 vuex@^3.4.0: